bug#41354: equal? has no sensible code path for symbols

Ludovic Courtès <[email protected]>
Newsgroups gmane.lisp.guile.bugs
Message-ID <[email protected]>
Hi,

David Kastrup <[email protected]> skribis:

> Ludovic Courtès <[email protected]> writes:
>
>> Hi David,
>>
>> David Kastrup <[email protected]> skribis:
>>
>>> In Scheme, symbols can be compared using eq? for equality.  However,
>>> since they have garbage-collected content attached, they do not meet the
>>> predicate SCM_IMP in the short-circuit evaluation at the start of equal?
>>> This means that unequal symbols compared using equal? fall through a
>>> whole bunch of tests and end up in a general structural comparison
>>> comparing their underlying string names.
>>
>> ‘equal?’ starts by checking for eq-ness, which LGTM:
>>
>>   SCM
>>   scm_equal_p (SCM x, SCM y)
>>   #define FUNC_NAME s_scm_i_equal_p
>>   {
>>     SCM_CHECK_STACK;
>>    tailrecurse:
>>     SCM_TICK;
>>     if (scm_is_eq (x, y))
>>       return SCM_BOOL_T;
>>
>> Or were you referring to something else?
>
> I repeat: "This means that UNEQUAL symbols compared using equal? fall
> through a whole bunch of tests and end up in a general structural
> comparison comparing their underlying string names".
>
> Lots of searches _end_ with an equal comparison (which is fast) but do a
> lot of unequal comparisons before that (which is slow, even though
> symbols that are not eq? will also not be equal?, so if you know you are
> checking _symbols_, if they are not eq? you are done).
>
> Symbols comparing as _unequal_ have no special path in equal?.

I was going to say that this is necessary for uninterned symbols, but it
turns out that uninterned symbols that look the same are not ‘equal?’:

--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> (define a (make-symbol "x"))
scheme@(guile-user)> (define b (make-symbol "x"))
scheme@(guile-user)> (eq? a b)
$10 = #f
scheme@(guile-user)> (equal? a b)
$11 = #f
--8<---------------cut here---------------end--------------->8---

Thus we could go with the patch below, though I doubt it would make a
measurable difference (and it actually adds tests for other cases).

Thoughts?

Besides, in the common case where one is comparing against a symbol
literal, the question is moot:

--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> ,optimize (equal? 'x s)
$14 = (eq? 'x s)
--8<---------------cut here---------------end--------------->8---

Ludo’.
(unnamed) (text/x-patch, 419 B)
diff --git a/libguile/eq.c b/libguile/eq.c
index 627d6f09b..16c5bfb3f 100644
--- a/libguile/eq.c
+++ b/libguile/eq.c
@@ -303,6 +303,8 @@ scm_equal_p (SCM x, SCM y)
     return SCM_BOOL_F;
   if (SCM_IMP (y))
     return SCM_BOOL_F;
+  if (scm_is_symbol (x) || scm_is_symbol (y))
+    return SCM_BOOL_F;
   if (scm_is_pair (x) && scm_is_pair (y))
     {
       if (scm_is_false (scm_equal_p (SCM_CAR (x), SCM_CAR (y))))
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.