* Surprising behavior of eq? @ 2020-09-20 12:16 Zelphir Kaltstahl 2020-09-20 12:19 ` Zelphir Kaltstahl 2020-09-20 17:26 ` Taylan Kammer 0 siblings, 2 replies; 13+ messages in thread From: Zelphir Kaltstahl @ 2020-09-20 12:16 UTC (permalink / raw) To: Guile User Hello Guile users, I just noticed something weird about eq?. My Guile version is: I get the different results, depending on whether I define some bindings in a let or using define: (In Emacs Geiser:) ~~~~ (define x '(10 9)) (define y '(10 9)) (eq? x y) $2 = #f (let ([x '(10 9)] [y '(10 9)]) (eq? x y)) $3 = #t ~~~~ Is this intentional or a bug? I first noticed something strange when writing the following code: ~~~~DEFINITION~~~~ (define make-multiple-list-remover (λ (equal-proc) (λ (lst unwanted) (let loop ([remaining-list lst]) (cond [(null? remaining-list) '()] [(equal-proc (car remaining-list) unwanted) (loop (cdr remaining-list))] [else (cons (car remaining-list) (loop (cdr remaining-list)))]))))) ~~~~ ~~~~TEST~~~~ (let ([a '(9 10)] [b '(9 10)]) (test-equal "make-multiple-list-remover-03" `(1 2 (3) (4) ,a) ((make-multiple-list-remover eq?) `(a b (c) (d) ,a) b))) ~~~~ I was wondering, why the test fails. I think (eq? ...) should not be able to see the equivalence of both lists a and b, just like when defined using (define ...). I can also run it in the REPL and see the difference: ~~~~ (define a '(9 10)) (define b '(9 10)) ((make-multiple-list-remover eq?) `(a b (c) (d) ,a) b) $4 = (a b (c) (d) (9 10)) (let ([a '(9 10)] [b '(9 10)]) ((make-multiple-list-remover eq?) `(a b (c) (d) ,a) b)) $5 = (a b (c) (d)) ~~~~ Somehow the bindings of let seem to be different from the bindings created using define. What about using define inside let? ~~~~ ~~~~ -- repositories: https://notabug.org/ZelphirKaltstahl ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 12:16 Surprising behavior of eq? Zelphir Kaltstahl @ 2020-09-20 12:19 ` Zelphir Kaltstahl 2020-09-20 12:58 ` Christopher Lemmer Webber 2020-09-20 13:09 ` Zelphir Kaltstahl 2020-09-20 17:26 ` Taylan Kammer 1 sibling, 2 replies; 13+ messages in thread From: Zelphir Kaltstahl @ 2020-09-20 12:19 UTC (permalink / raw) To: Guile User Sorry, I misclicked "send" when I wanted to further edit my e-mail ... My Guile version is: ~~~~ (version) $6 = "3.0.4" ~~~~ On 20.09.20 14:16, Zelphir Kaltstahl wrote: > > Hello Guile users, > > I just noticed something weird about eq?. > > My Guile version is: > > > I get the different results, depending on whether I define some > bindings in a let or using define: > > (In Emacs Geiser:) > > ~~~~ > (define x '(10 9)) > (define y '(10 9)) > (eq? x y) > $2 = #f > > (let ([x '(10 9)] > [y '(10 9)]) > (eq? x y)) > $3 = #t > ~~~~ > > Is this intentional or a bug? > > I first noticed something strange when writing the following code: > > ~~~~DEFINITION~~~~ > (define make-multiple-list-remover > (λ (equal-proc) > (λ (lst unwanted) > (let loop ([remaining-list lst]) > (cond > [(null? remaining-list) > '()] > [(equal-proc (car remaining-list) unwanted) > (loop (cdr remaining-list))] > [else > (cons (car remaining-list) > (loop (cdr remaining-list)))]))))) > ~~~~ > > ~~~~TEST~~~~ > (let ([a '(9 10)] > [b '(9 10)]) > (test-equal "make-multiple-list-remover-03" > `(1 2 (3) (4) ,a) > ((make-multiple-list-remover eq?) > `(a b (c) (d) ,a) b))) > ~~~~ > > I was wondering, why the test fails. I think (eq? ...) should not be > able to see the equivalence of both lists a and b, just like when > defined using (define ...). > > I can also run it in the REPL and see the difference: > > ~~~~ > (define a '(9 10)) > (define b '(9 10)) > ((make-multiple-list-remover eq?) > `(a b (c) (d) ,a) b) > $4 = (a b (c) (d) (9 10)) > > (let ([a '(9 10)] > [b '(9 10)]) > ((make-multiple-list-remover eq?) > `(a b (c) (d) ,a) b)) > $5 = (a b (c) (d)) > ~~~~ > > Somehow the bindings of let seem to be different from the bindings > created using define. What about using define inside let? > > ~~~~ > > ~~~~ > -- > repositories: https://notabug.org/ZelphirKaltstahl Somehow the bindings of let seem to be different from the bindings created using define. What about using define inside let? ~~~~ (let ([unrelated 'bla]) (define a '(9 10)) (define b '(9 10)) ((make-multiple-list-remover eq?) `(a b (c) (d) ,a) b)) $7 = (a b (c) (d)) ~~~~ So there the define usage also differs from when I use define on the top level. Perhaps that is the difference? On which level the bindings are defined? Regards, Zelphir -- repositories: https://notabug.org/ZelphirKaltstahl ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 12:19 ` Zelphir Kaltstahl @ 2020-09-20 12:58 ` Christopher Lemmer Webber 2020-09-20 13:09 ` Zelphir Kaltstahl 1 sibling, 0 replies; 13+ messages in thread From: Christopher Lemmer Webber @ 2020-09-20 12:58 UTC (permalink / raw) To: Zelphir Kaltstahl; +Cc: guile-user My guess, without really knowing, is this is some sort of optimization. But it could affect things I suppose if someone is intending to construct lists for the main purpose of creating different eq-differentiated identifiers (eg as keys for a hasheq)... Zelphir Kaltstahl writes: > Sorry, I misclicked "send" when I wanted to further edit my e-mail ... > > My Guile version is: > > ~~~~ > (version) > $6 = "3.0.4" > ~~~~ > > On 20.09.20 14:16, Zelphir Kaltstahl wrote: >> >> Hello Guile users, >> >> I just noticed something weird about eq?. >> >> My Guile version is: >> >> >> I get the different results, depending on whether I define some >> bindings in a let or using define: >> >> (In Emacs Geiser:) >> >> ~~~~ >> (define x '(10 9)) >> (define y '(10 9)) >> (eq? x y) >> $2 = #f >> >> (let ([x '(10 9)] >> [y '(10 9)]) >> (eq? x y)) >> $3 = #t >> ~~~~ >> >> Is this intentional or a bug? >> >> I first noticed something strange when writing the following code: >> >> ~~~~DEFINITION~~~~ >> (define make-multiple-list-remover >> (λ (equal-proc) >> (λ (lst unwanted) >> (let loop ([remaining-list lst]) >> (cond >> [(null? remaining-list) >> '()] >> [(equal-proc (car remaining-list) unwanted) >> (loop (cdr remaining-list))] >> [else >> (cons (car remaining-list) >> (loop (cdr remaining-list)))]))))) >> ~~~~ >> >> ~~~~TEST~~~~ >> (let ([a '(9 10)] >> [b '(9 10)]) >> (test-equal "make-multiple-list-remover-03" >> `(1 2 (3) (4) ,a) >> ((make-multiple-list-remover eq?) >> `(a b (c) (d) ,a) b))) >> ~~~~ >> >> I was wondering, why the test fails. I think (eq? ...) should not be >> able to see the equivalence of both lists a and b, just like when >> defined using (define ...). >> >> I can also run it in the REPL and see the difference: >> >> ~~~~ >> (define a '(9 10)) >> (define b '(9 10)) >> ((make-multiple-list-remover eq?) >> `(a b (c) (d) ,a) b) >> $4 = (a b (c) (d) (9 10)) >> >> (let ([a '(9 10)] >> [b '(9 10)]) >> ((make-multiple-list-remover eq?) >> `(a b (c) (d) ,a) b)) >> $5 = (a b (c) (d)) >> ~~~~ >> >> Somehow the bindings of let seem to be different from the bindings >> created using define. What about using define inside let? >> >> ~~~~ >> >> ~~~~ >> -- >> repositories: https://notabug.org/ZelphirKaltstahl > > Somehow the bindings of let seem to be different from the bindings > created using define. What about using define inside let? > > ~~~~ > (let ([unrelated 'bla]) > (define a '(9 10)) > (define b '(9 10)) > ((make-multiple-list-remover eq?) > `(a b (c) (d) ,a) b)) > $7 = (a b (c) (d)) > ~~~~ > > So there the define usage also differs from when I use define on the top > level. Perhaps that is the difference? On which level the bindings are > defined? > > Regards, > Zelphir ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 12:19 ` Zelphir Kaltstahl 2020-09-20 12:58 ` Christopher Lemmer Webber @ 2020-09-20 13:09 ` Zelphir Kaltstahl 2020-09-20 13:52 ` John Cowan 2020-09-20 13:57 ` Stefan Schmiedl 1 sibling, 2 replies; 13+ messages in thread From: Zelphir Kaltstahl @ 2020-09-20 13:09 UTC (permalink / raw) To: guile-user And I've noticed something more about equality stuff in the context of tests: ~~~~ (eqv? "a" "a") $3 = #t ;; but (define char->string (λ (c) (list->string (list c)))) (import ;; unit tests (srfi srfi-64)) (test-begin "string-utils-test") (test-group "char-to-string-test" (test-eqv "char->string converts a character to a string" "a" (char->string #\a))) (test-end "string-utils-test") %%%% Starting test string-utils-test (Writing full log to "string-utils-test.log") $2 = ("string-utils-test") :19: FAIL char->string converts a character to a string # of unexpected failures 1 ~~~~ So while (eqv? ...) gives the correct (?) result, the test procedure (test-eqv ...) which seems to indicate using (eqv? ...) via its name does not think of the two strings as equivalent. On 20.09.20 14:19, Zelphir Kaltstahl wrote: > Sorry, I misclicked "send" when I wanted to further edit my e-mail ... > > My Guile version is: > > ~~~~ > (version) > $6 = "3.0.4" > ~~~~ > > On 20.09.20 14:16, Zelphir Kaltstahl wrote: >> Hello Guile users, >> >> I just noticed something weird about eq?. >> >> My Guile version is: >> >> >> I get the different results, depending on whether I define some >> bindings in a let or using define: >> >> (In Emacs Geiser:) >> >> ~~~~ >> (define x '(10 9)) >> (define y '(10 9)) >> (eq? x y) >> $2 = #f >> >> (let ([x '(10 9)] >> [y '(10 9)]) >> (eq? x y)) >> $3 = #t >> ~~~~ >> >> Is this intentional or a bug? >> >> I first noticed something strange when writing the following code: >> >> ~~~~DEFINITION~~~~ >> (define make-multiple-list-remover >> (λ (equal-proc) >> (λ (lst unwanted) >> (let loop ([remaining-list lst]) >> (cond >> [(null? remaining-list) >> '()] >> [(equal-proc (car remaining-list) unwanted) >> (loop (cdr remaining-list))] >> [else >> (cons (car remaining-list) >> (loop (cdr remaining-list)))]))))) >> ~~~~ >> >> ~~~~TEST~~~~ >> (let ([a '(9 10)] >> [b '(9 10)]) >> (test-equal "make-multiple-list-remover-03" >> `(1 2 (3) (4) ,a) >> ((make-multiple-list-remover eq?) >> `(a b (c) (d) ,a) b))) >> ~~~~ >> >> I was wondering, why the test fails. I think (eq? ...) should not be >> able to see the equivalence of both lists a and b, just like when >> defined using (define ...). >> >> I can also run it in the REPL and see the difference: >> >> ~~~~ >> (define a '(9 10)) >> (define b '(9 10)) >> ((make-multiple-list-remover eq?) >> `(a b (c) (d) ,a) b) >> $4 = (a b (c) (d) (9 10)) >> >> (let ([a '(9 10)] >> [b '(9 10)]) >> ((make-multiple-list-remover eq?) >> `(a b (c) (d) ,a) b)) >> $5 = (a b (c) (d)) >> ~~~~ >> >> Somehow the bindings of let seem to be different from the bindings >> created using define. What about using define inside let? >> >> ~~~~ >> >> ~~~~ >> -- >> repositories: https://notabug.org/ZelphirKaltstahl > Somehow the bindings of let seem to be different from the bindings > created using define. What about using define inside let? > > ~~~~ > (let ([unrelated 'bla]) > (define a '(9 10)) > (define b '(9 10)) > ((make-multiple-list-remover eq?) > `(a b (c) (d) ,a) b)) > $7 = (a b (c) (d)) > ~~~~ > > So there the define usage also differs from when I use define on the top > level. Perhaps that is the difference? On which level the bindings are > defined? > > Regards, > Zelphir > -- repositories: https://notabug.org/ZelphirKaltstahl ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 13:09 ` Zelphir Kaltstahl @ 2020-09-20 13:52 ` John Cowan 2020-09-20 15:37 ` Zelphir Kaltstahl 2020-09-20 13:57 ` Stefan Schmiedl 1 sibling, 1 reply; 13+ messages in thread From: John Cowan @ 2020-09-20 13:52 UTC (permalink / raw) To: Zelphir Kaltstahl; +Cc: guile-user What's happening is that you are trying to compare strings with an inappropriate predicate. Eqv? tests for *identity* (being the same object), whereas equal? tests for *equality* (havng the same structure). Therefore, (equal? "foo" "foo") will always return #t, and almost all the time that's the predicate you should use. The question then is: when are two strings identical and not merely equal? In the general case, they are identical if they are the result of a single constructor. Thus given: (define a (string #\a #\b #\c)) (define b a) then (eqv? a b) => #t But given (define c (string #\a #\b #c)) (define d (string #\a #\b #c)) then (eqv? c d) => #f Finally, we have to deal with string literals. If there is more than one appearance of "xyz" in code, they are all equal, but are they identical? The answer is that it is implementation-dependent. A Scheme is free to consolidate all equal literals into the same object. It looks like Guile does so when they both appear in the same top-level expression, but *not* in different top-level expressions. So given (define e "xyz") (define f "xyz") then (eqv? e f) => #f But (let ((g "xyz") (h "xyz")) (eqv? g h)) => #t, because Guile consolidates the two equal literals into a single object. If you try this on Chibi Scheme, you'll get #f, because Chibi does *not* consolidate string literals. I hope that is helpful. On Sun, Sep 20, 2020 at 9:11 AM Zelphir Kaltstahl < zelphirkaltstahl@posteo.de> wrote: > And I've noticed something more about equality stuff in the context of > tests: > > ~~~~ > (eqv? "a" "a") > $3 = #t > > ;; but > > (define char->string > (λ (c) > (list->string > (list c)))) > > (import > ;; unit tests > (srfi srfi-64)) > > (test-begin "string-utils-test") > > (test-group > "char-to-string-test" > > (test-eqv "char->string converts a character to a string" > "a" > (char->string #\a))) > > (test-end "string-utils-test") > > %%%% Starting test string-utils-test (Writing full log to > "string-utils-test.log") > $2 = ("string-utils-test") > :19: FAIL char->string converts a character to a string > # of unexpected failures 1 > ~~~~ > > So while (eqv? ...) gives the correct (?) result, the test procedure > (test-eqv ...) which seems to indicate using (eqv? ...) via its name > does not think of the two strings as equivalent. > > > On 20.09.20 14:19, Zelphir Kaltstahl wrote: > > Sorry, I misclicked "send" when I wanted to further edit my e-mail ... > > > > My Guile version is: > > > > ~~~~ > > (version) > > $6 = "3.0.4" > > ~~~~ > > > > On 20.09.20 14:16, Zelphir Kaltstahl wrote: > >> Hello Guile users, > >> > >> I just noticed something weird about eq?. > >> > >> My Guile version is: > >> > >> > >> I get the different results, depending on whether I define some > >> bindings in a let or using define: > >> > >> (In Emacs Geiser:) > >> > >> ~~~~ > >> (define x '(10 9)) > >> (define y '(10 9)) > >> (eq? x y) > >> $2 = #f > >> > >> (let ([x '(10 9)] > >> [y '(10 9)]) > >> (eq? x y)) > >> $3 = #t > >> ~~~~ > >> > >> Is this intentional or a bug? > >> > >> I first noticed something strange when writing the following code: > >> > >> ~~~~DEFINITION~~~~ > >> (define make-multiple-list-remover > >> (λ (equal-proc) > >> (λ (lst unwanted) > >> (let loop ([remaining-list lst]) > >> (cond > >> [(null? remaining-list) > >> '()] > >> [(equal-proc (car remaining-list) unwanted) > >> (loop (cdr remaining-list))] > >> [else > >> (cons (car remaining-list) > >> (loop (cdr remaining-list)))]))))) > >> ~~~~ > >> > >> ~~~~TEST~~~~ > >> (let ([a '(9 10)] > >> [b '(9 10)]) > >> (test-equal "make-multiple-list-remover-03" > >> `(1 2 (3) (4) ,a) > >> ((make-multiple-list-remover eq?) > >> `(a b (c) (d) ,a) b))) > >> ~~~~ > >> > >> I was wondering, why the test fails. I think (eq? ...) should not be > >> able to see the equivalence of both lists a and b, just like when > >> defined using (define ...). > >> > >> I can also run it in the REPL and see the difference: > >> > >> ~~~~ > >> (define a '(9 10)) > >> (define b '(9 10)) > >> ((make-multiple-list-remover eq?) > >> `(a b (c) (d) ,a) b) > >> $4 = (a b (c) (d) (9 10)) > >> > >> (let ([a '(9 10)] > >> [b '(9 10)]) > >> ((make-multiple-list-remover eq?) > >> `(a b (c) (d) ,a) b)) > >> $5 = (a b (c) (d)) > >> ~~~~ > >> > >> Somehow the bindings of let seem to be different from the bindings > >> created using define. What about using define inside let? > >> > >> ~~~~ > >> > >> ~~~~ > >> -- > >> repositories: https://notabug.org/ZelphirKaltstahl > > Somehow the bindings of let seem to be different from the bindings > > created using define. What about using define inside let? > > > > ~~~~ > > (let ([unrelated 'bla]) > > (define a '(9 10)) > > (define b '(9 10)) > > ((make-multiple-list-remover eq?) > > `(a b (c) (d) ,a) b)) > > $7 = (a b (c) (d)) > > ~~~~ > > > > So there the define usage also differs from when I use define on the top > > level. Perhaps that is the difference? On which level the bindings are > > defined? > > > > Regards, > > Zelphir > > > -- > repositories: https://notabug.org/ZelphirKaltstahl > > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 13:52 ` John Cowan @ 2020-09-20 15:37 ` Zelphir Kaltstahl 2020-09-20 16:18 ` tomas 2020-09-20 17:05 ` John Cowan 0 siblings, 2 replies; 13+ messages in thread From: Zelphir Kaltstahl @ 2020-09-20 15:37 UTC (permalink / raw) To: John Cowan; +Cc: guile-user Hello John, hello Stefan! My previous understanding, it seems, was too shallow to explain the behavior I saw. I think I misread https://stackoverflow.com/a/17719745/1829329, where it says: "This is where the eqv? predicate comes into picture. The eqv? is exactly the same as the eq? predicate, except that it will always return #t for same primitive values." Of course SO is not a standard. Either it is simply wrong, or I misunderstood "primitive values" in that phrase. I thought: "Ah strings are a primitive value, so eqv? should work in all cases when comparing strings." However, this has been debunked. Anyway, your explanation makes sense to me and I learned something new: Schemes differ in the way they "consolidate" literals. I know Racket says it is not a Scheme any longer, but I still tried: ~~~~ Welcome to Racket v7.0. > (let ((g "xyz") (h "xyz")) (eqv? g h)) #t > (define g "xyz") > (define h "xyz") > (eqv? g h) #t > ~~~~ So it seems Racket consolidates literals from multiple top level expressions. While in GNU Guile: ~~~~ scheme@(guile-user)> (let ((g "xyz") (h "xyz")) (eqv? g h)) $1 = #t scheme@(guile-user)> (define g "xyz") scheme@(guile-user)> (define h "xyz") scheme@(guile-user)> (eqv? g h) $2 = #f scheme@(guile-user)> ~~~~ So there we have a difference in how literals are consolidated in GNU Guile and Racket. Interesting! Thank you for your explanation! The only thing I do not quite understand yet is: What is the difference between (eqv? ...) and (eq? ...) then? If (eqv? ...) is only #t if things get consolidated in the same store place, would that not be the same as pointer equivalence? Ah, OK, the difference is, that (eqv? ...) works for numbers, regardless of whether they are consolidated, while eq? does not recognize them as equivalent: ~~~~ (define a 3.0) (define b 3.0) (eq? a b) $6 = #f (eqv? a b) $7 = #t ~~~~ So even if they are not consolidated (put in the same store), (eqv? ...) has some internal logic to treat numbers differently, while (eq? ...) does not do that. In the Guile manual there is no example given, for which (eq? ...) and (eqv? ...) give different results: https://www.gnu.org/software/guile/manual/html_node/Equality.html. When I try the example given for (eq? ...), I get the same results for (eqv? ...): ~~~~ (define x (vector 1 2 3)) (define y (vector 1 2 3)) (eq? x x) ⇒ #t (eq? x y) ⇒ #f (eqv? x x) ⇒ #t (eqv? x y) ⇒ #f ~~~~ I also read Stefan's explanation, which seems to boil down to the same thing: Same or different locations in the "store". Also that (eqv? ...) is not the correct thing to use for strings. Best regards, Zelphir On 9/20/20 3:52 PM, John Cowan wrote: > What's happening is that you are trying to compare strings with an > inappropriate predicate. Eqv? tests for *identity* (being the same > object), whereas equal? tests for *equality* (havng the same > structure). Therefore, (equal? "foo" "foo") will always return #t, > and almost all the time that's the predicate you should use. > > The question then is: when are two strings identical and not merely > equal? In the general case, they are identical if they are the result > of a single constructor. Thus given: > > (define a (string #\a #\b #\c)) > (define b a) > > then (eqv? a b) => #t > > But given > > (define c (string #\a #\b #c)) > (define d (string #\a #\b #c)) > > then (eqv? c d) => #f > > Finally, we have to deal with string literals. If there is more than > one appearance of "xyz" in code, they are all equal, but are they > identical? The answer is that it is implementation-dependent. A > Scheme is free to consolidate all equal literals into the same > object. It looks like Guile does so when they both appear in the same > top-level expression, but *not* in different top-level expressions. > So given > > (define e "xyz") > (define f "xyz") > > then (eqv? e f) => #f > > But (let ((g "xyz") (h "xyz")) (eqv? g h)) => #t, because Guile > consolidates the two equal literals into a single object. If you try > this on Chibi Scheme, you'll get #f, because Chibi does *not* > consolidate string literals. > > I hope that is helpful. > > > > > On Sun, Sep 20, 2020 at 9:11 AM Zelphir Kaltstahl > <zelphirkaltstahl@posteo.de <mailto:zelphirkaltstahl@posteo.de>> wrote: > > And I've noticed something more about equality stuff in the context of > tests: > > ~~~~ > (eqv? "a" "a") > $3 = #t > > ;; but > > (define char->string > (λ (c) > (list->string > (list c)))) > > (import > ;; unit tests > (srfi srfi-64)) > > (test-begin "string-utils-test") > > (test-group > "char-to-string-test" > > (test-eqv "char->string converts a character to a string" > "a" > (char->string #\a))) > > (test-end "string-utils-test") > > %%%% Starting test string-utils-test (Writing full log to > "string-utils-test.log") > $2 = ("string-utils-test") > :19: FAIL char->string converts a character to a string > # of unexpected failures 1 > ~~~~ > > So while (eqv? ...) gives the correct (?) result, the test procedure > (test-eqv ...) which seems to indicate using (eqv? ...) via its name > does not think of the two strings as equivalent. > > > On 20.09.20 14:19, Zelphir Kaltstahl wrote: > > Sorry, I misclicked "send" when I wanted to further edit my > e-mail ... > > > > My Guile version is: > > > > ~~~~ > > (version) > > $6 = "3.0.4" > > ~~~~ > > > > On 20.09.20 14:16, Zelphir Kaltstahl wrote: > >> Hello Guile users, > >> > >> I just noticed something weird about eq?. > >> > >> My Guile version is: > >> > >> > >> I get the different results, depending on whether I define some > >> bindings in a let or using define: > >> > >> (In Emacs Geiser:) > >> > >> ~~~~ > >> (define x '(10 9)) > >> (define y '(10 9)) > >> (eq? x y) > >> $2 = #f > >> > >> (let ([x '(10 9)] > >> [y '(10 9)]) > >> (eq? x y)) > >> $3 = #t > >> ~~~~ > >> > >> Is this intentional or a bug? > >> > >> I first noticed something strange when writing the following code: > >> > >> ~~~~DEFINITION~~~~ > >> (define make-multiple-list-remover > >> (λ (equal-proc) > >> (λ (lst unwanted) > >> (let loop ([remaining-list lst]) > >> (cond > >> [(null? remaining-list) > >> '()] > >> [(equal-proc (car remaining-list) unwanted) > >> (loop (cdr remaining-list))] > >> [else > >> (cons (car remaining-list) > >> (loop (cdr remaining-list)))]))))) > >> ~~~~ > >> > >> ~~~~TEST~~~~ > >> (let ([a '(9 10)] > >> [b '(9 10)]) > >> (test-equal "make-multiple-list-remover-03" > >> `(1 2 (3) (4) ,a) > >> ((make-multiple-list-remover eq?) > >> `(a b (c) (d) ,a) b))) > >> ~~~~ > >> > >> I was wondering, why the test fails. I think (eq? ...) should > not be > >> able to see the equivalence of both lists a and b, just like when > >> defined using (define ...). > >> > >> I can also run it in the REPL and see the difference: > >> > >> ~~~~ > >> (define a '(9 10)) > >> (define b '(9 10)) > >> ((make-multiple-list-remover eq?) > >> `(a b (c) (d) ,a) b) > >> $4 = (a b (c) (d) (9 10)) > >> > >> (let ([a '(9 10)] > >> [b '(9 10)]) > >> ((make-multiple-list-remover eq?) > >> `(a b (c) (d) ,a) b)) > >> $5 = (a b (c) (d)) > >> ~~~~ > >> > >> Somehow the bindings of let seem to be different from the bindings > >> created using define. What about using define inside let? > >> > >> ~~~~ > >> > >> ~~~~ > >> -- > >> repositories: https://notabug.org/ZelphirKaltstahl > > Somehow the bindings of let seem to be different from the bindings > > created using define. What about using define inside let? > > > > ~~~~ > > (let ([unrelated 'bla]) > > (define a '(9 10)) > > (define b '(9 10)) > > ((make-multiple-list-remover eq?) > > `(a b (c) (d) ,a) b)) > > $7 = (a b (c) (d)) > > ~~~~ > > > > So there the define usage also differs from when I use define on > the top > > level. Perhaps that is the difference? On which level the > bindings are > > defined? > > > > Regards, > > Zelphir > > > -- > repositories: https://notabug.org/ZelphirKaltstahl > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 15:37 ` Zelphir Kaltstahl @ 2020-09-20 16:18 ` tomas 2020-09-20 17:05 ` John Cowan 1 sibling, 0 replies; 13+ messages in thread From: tomas @ 2020-09-20 16:18 UTC (permalink / raw) To: guile-user [-- Attachment #1: Type: text/plain, Size: 957 bytes --] On Sun, Sep 20, 2020 at 05:37:45PM +0200, Zelphir Kaltstahl wrote: > Hello John, hello Stefan! [...] > Of course SO is not a standard. Either it is simply wrong, or I > misunderstood "primitive values" in that phrase. I thought: "Ah strings > are a primitive value, so eqv? should work in all cases when comparing > strings." However, this has been debunked. Strings are mutable in Guile, so probably not what's called "primitive values": scheme@(guile-user)> (define str (string-copy "the quick brown fox")) scheme@(guile-user)> (string-set! str 6 #\a) scheme@(guile-user)> str $3 = "the quack brown fox" But string literals bark at you if you try to mutate them (that's why I slyly created that one with `string-copy'): scheme@(guile-user)> (define str "the quick brown fox") scheme@(guile-user)> (string-set! str 6 #\a) ice-9/boot-9.scm:1669:16: In procedure raise-exception: string is read-only: "the quick brown fox" Cheers - t [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 198 bytes --] ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 15:37 ` Zelphir Kaltstahl 2020-09-20 16:18 ` tomas @ 2020-09-20 17:05 ` John Cowan 2020-09-20 20:51 ` Linus Björnstam 1 sibling, 1 reply; 13+ messages in thread From: John Cowan @ 2020-09-20 17:05 UTC (permalink / raw) To: Zelphir Kaltstahl; +Cc: guile-user On Sun, Sep 20, 2020 at 11:37 AM Zelphir Kaltstahl < zelphirkaltstahl@posteo.de> wrote: > "This is where the eqv? predicate comes into picture. The eqv? is exactly > the same as the eq? predicate, except that it will always return #t for > same primitive values." > > Of course SO is not a standard. Either it is simply wrong, or I > misunderstood "primitive values" in that phrase. I thought: "Ah strings are > a primitive value, so eqv? should work in all cases when comparing > strings." However, this has been debunked. > Strings tend to be treated as primitive values, but technically they are compound values, just as much as vectors are. And like vectors, you can change the characters of a string without changing its identity. > The only thing I do not quite understand yet is: What is the difference > between (eqv? ...) and (eq? ...) then? > Efficiency only. > If (eqv? ...) is only #t if things get consolidated in the same store > place, would that not be the same as pointer equivalence? > Eq? is allowed to return #f on identical-looking characters and numbers because they may or may not involve allocation. Characters and fixnums (integers up to about 2^60) are generally not allocated and eq? will return #t on them, but larger integers and other types almost certainly will not: (let ((i (* 48923498234892340 78902372789023)) (j (* 48923498234892340 78902372789023))) (eq? i j)) => #f That's because the values of both i and j have to be allocated, and therefore aren't represented by the same pointers. But unlike strings, you can't mutate the digits of an integer, so providing eqv? gives us an abstract notion of identity. The Scheme standards simplify the situation by saying that eq? may return #f even when eqv? returns #t in the cases of numbers and characters. Because of these strange effects, I recommend (and this is just me) not using eq? unless you can prove that you need the additional effi. Note that (eq? 5 5.0) and (eqv? 5 5.0) are both #f, so if you want to compare for numeric equality you should use (= 5 5.0) => #t. The reason they are not identical is that they behave differently: (/ 5.0 2) => 2.5, whereas (/ 5 2) => 5/2. Here's an example that shows us that Guile does not consolidate number literals, although it could: (eqv? 3860180095872584138419938783820 3860180095872584138419938783820) =>#f (In R7RS, procedures that are eqv? aren't necessarily eq? either, and in R6RS even procedures that seem totally identical may be neither eq? nor eqv?. That's another story.) ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 17:05 ` John Cowan @ 2020-09-20 20:51 ` Linus Björnstam 2020-09-20 21:42 ` John Cowan 0 siblings, 1 reply; 13+ messages in thread From: Linus Björnstam @ 2020-09-20 20:51 UTC (permalink / raw) To: John Cowan, Zelphir Kaltstahl; +Cc: guile-user Just a quick note on guile: if you are testing equality against literals guile will optimize to the fastest kind. (equal? b 27) becomes (eq? b 27). This was added by Andy sometime since 3.0, after Aleix discovered that match was slower than cond-with-eqv? for chars, and that the difference was huge. I wrote an awful patch, which made Andy barf so he fixed it properly (no. He was very polite. If he barfed, he didn't mention it). A simple optimization that shaved something like 15% of time spent in json->scm in guile-json on one of the files we used for benchmarking. It was converted to cond for the benefit of 2.2, though, but it is still a nice thing to be able to rely on when writing macros. -- Linus Björnstam On Sun, 20 Sep 2020, at 19:05, John Cowan wrote: > On Sun, Sep 20, 2020 at 11:37 AM Zelphir Kaltstahl < > zelphirkaltstahl@posteo.de> wrote: > > > "This is where the eqv? predicate comes into picture. The eqv? is exactly > > the same as the eq? predicate, except that it will always return #t for > > same primitive values." > > > > Of course SO is not a standard. Either it is simply wrong, or I > > misunderstood "primitive values" in that phrase. I thought: "Ah strings are > > a primitive value, so eqv? should work in all cases when comparing > > strings." However, this has been debunked. > > > Strings tend to be treated as primitive values, but technically they are > compound values, just as much as vectors are. And like vectors, you can > change the characters of a string without changing its identity. > > > The only thing I do not quite understand yet is: What is the difference > > between (eqv? ...) and (eq? ...) then? > > > Efficiency only. > > > If (eqv? ...) is only #t if things get consolidated in the same store > > place, would that not be the same as pointer equivalence? > > > Eq? is allowed to return #f on identical-looking characters and numbers > because they may or may not involve allocation. Characters and fixnums > (integers up to about 2^60) are generally not allocated and eq? will return > #t on them, but larger integers and other types almost certainly will not: > > (let ((i (* 48923498234892340 78902372789023)) (j (* 48923498234892340 > 78902372789023))) (eq? i j)) => #f > > That's because the values of both i and j have to be allocated, and > therefore aren't represented by the same pointers. But unlike strings, you > can't mutate the digits of an integer, so providing eqv? gives us an > abstract notion of identity. The Scheme standards simplify the situation > by saying that eq? may return #f even when eqv? returns #t in the cases of > numbers and characters. > > Because of these strange effects, I recommend (and this is just me) not > using eq? unless you can prove that you need the additional effi. > > Note that (eq? 5 5.0) and (eqv? 5 5.0) are both #f, so if you want to > compare for numeric equality you should use (= 5 5.0) => #t. The reason > they are not identical is that they behave differently: (/ 5.0 2) => 2.5, > whereas (/ 5 2) => 5/2. > > Here's an example that shows us that Guile does not consolidate number > literals, although it could: > > (eqv? 3860180095872584138419938783820 3860180095872584138419938783820) =>#f > > (In R7RS, procedures that are eqv? aren't necessarily eq? either, and in > R6RS even procedures that seem totally identical may be neither eq? nor > eqv?. That's another story.) > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 20:51 ` Linus Björnstam @ 2020-09-20 21:42 ` John Cowan 0 siblings, 0 replies; 13+ messages in thread From: John Cowan @ 2020-09-20 21:42 UTC (permalink / raw) To: Linus Björnstam; +Cc: guile-user On Sun, Sep 20, 2020 at 4:52 PM Linus Björnstam <linus.internet@fastmail.se> wrote: Just a quick note on guile: if you are testing equality against literals > guile will optimize to the fastest kind. (equal? b 27) becomes (eq? b 27). Indeed, it's a Good Thing if equal? starts out with an eqv? test (which should be inlined except for number comparisons) and eqv? starts out with an eq? test (which also should be inlined). If the more fine-grained test returns #t, the more coarse-grained one can safely return #t also. This is independent of literals, and should IMO be done by every Scheme. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 13:09 ` Zelphir Kaltstahl 2020-09-20 13:52 ` John Cowan @ 2020-09-20 13:57 ` Stefan Schmiedl 2020-09-20 15:42 ` Zelphir Kaltstahl 1 sibling, 1 reply; 13+ messages in thread From: Stefan Schmiedl @ 2020-09-20 13:57 UTC (permalink / raw) To: Zelphir Kaltstahl, guile-user Let's have a little shop talk with guile: $ guile-3.0 GNU Guile 3.0.4-dirty scheme@(guile-user)> (eqv? "a" "a") $1 = #t Hypothesis: guile's reader recognizes that the contents of both string literals are the same and feeds the same string to the calling function. Check: If that were the case, the two strings should not only be eqv? but also eq? scheme@(guile-user)> (eq? "a" "a") $2 = #t To see a different behaviour we need to avoid these literals and replace them by values not built while reading but while executing the code: scheme@(guile-user)> (equal? (list->string (list #\a)) (list->string (list #\a))) $3 = #t Now we compare two different string values which happen to end up with identical content. And, behold: They are neither eqv? nor eq?. scheme@(guile-user)> (eqv? (list->string (list #\a)) (list->string (list #\a))) $4 = #f scheme@(guile-user)> (eq? (list->string (list #\a)) (list->string (list #\a))) $5 = #f Now let's see if that is consistent with the standard: According to r5rs, section 6.1 "Equivalence predicates": The eqv? procedure returns #t if: ... * obj1 and obj2 are pairs, vectors, or strings that denote the same locations in the store (section 3.4). So we have learned * that guile's reader reuses "store locations" for strings of identical content * that eqv? is not the right predicate for content based string comparison HTH s. "Zelphir Kaltstahl" <zelphirkaltstahl@posteo.de>, 20.09.2020, 15:09: > And I've noticed something more about equality stuff in the context of > tests: > ~~~~ > (eqv? "a" "a") > $3 = #t > ;; but (define char->>string > (λ (c) > (list->string > (list c)))) > (import > ;; unit tests > (srfi srfi-64)) > (test-begin "string-utils-test") > (test-group > "char-to-string-test" > (test-eqv "char->string converts a character to a string" > "a" > (char->string #\a))) > (test-end "string-utils-test") > %%%% Starting test string-utils-test (Writing full log to "string-utils-test.log") > $2 = ("string-utils-test") :19: FAIL char->>string converts a character to a string > # of unexpected failures 1 > ~~~~ > So while (eqv? ...) gives the correct (?) result, the test procedure > (test-eqv ...) which seems to indicate using (eqv? ...) via its name > does not think of the two strings as equivalent. > On 20.09.20 14:19, Zelphir Kaltstahl wrote: >> Sorry, I misclicked "send" when I wanted to further edit my e-mail ... >> >> My Guile version is: >> >> ~~~~ >> (version) >> $6 = "3.0.4" >> ~~~~ >> >> On 20.09.20 14:16, Zelphir Kaltstahl wrote: >>> Hello Guile users, >>> >>> I just noticed something weird about eq?. >>> >>> My Guile version is: >>> >>> >>> I get the different results, depending on whether I define some >>> bindings in a let or using define: >>> >>> (In Emacs Geiser:) >>> >>> ~~~~ >>> (define x '(10 9)) >>> (define y '(10 9)) >>> (eq? x y) >>> $2 = #f >>> >>> (let ([x '(10 9)] >>> [y '(10 9)]) >>> (eq? x y)) >>> $3 = #t >>> ~~~~ >>> >>> Is this intentional or a bug? >>> >>> I first noticed something strange when writing the following code: >>> >>> ~~~~DEFINITION~~~~ >>> (define make-multiple-list-remover >>> (λ (equal-proc) >>> (λ (lst unwanted) >>> (let loop ([remaining-list lst]) >>> (cond >>> [(null? remaining-list) >>> '()] >>> [(equal-proc (car remaining-list) unwanted) >>> (loop (cdr remaining-list))] >>> [else >>> (cons (car remaining-list) >>> (loop (cdr remaining-list)))]))))) >>> ~~~~ >>> >>> ~~~~TEST~~~~ >>> (let ([a '(9 10)] >>> [b '(9 10)]) >>> (test-equal "make-multiple-list-remover-03" >>> `(1 2 (3) (4) ,a) >>> ((make-multiple-list-remover eq?) >>> `(a b (c) (d) ,a) b))) >>> ~~~~ >>> >>> I was wondering, why the test fails. I think (eq? ...) should not be >>> able to see the equivalence of both lists a and b, just like when >>> defined using (define ...). >>> >>> I can also run it in the REPL and see the difference: >>> >>> ~~~~ >>> (define a '(9 10)) >>> (define b '(9 10)) >>> ((make-multiple-list-remover eq?) >>> `(a b (c) (d) ,a) b) >>> $4 = (a b (c) (d) (9 10)) >>> >>> (let ([a '(9 10)] >>> [b '(9 10)]) >>> ((make-multiple-list-remover eq?) >>> `(a b (c) (d) ,a) b)) >>> $5 = (a b (c) (d)) >>> ~~~~ >>> >>> Somehow the bindings of let seem to be different from the bindings >>> created using define. What about using define inside let? >>> >>> ~~~~ >>> >>> ~~~~ >>> -- >>> repositories: https://notabug.org/ZelphirKaltstahl >> Somehow the bindings of let seem to be different from the bindings >> created using define. What about using define inside let? >> >> ~~~~ >> (let ([unrelated 'bla]) >> (define a '(9 10)) >> (define b '(9 10)) >> ((make-multiple-list-remover eq?) >> `(a b (c) (d) ,a) b)) >> $7 = (a b (c) (d)) >> ~~~~ >> >> So there the define usage also differs from when I use define on the top >> level. Perhaps that is the difference? On which level the bindings are >> defined? >> >> Regards, >> Zelphir >> -- Stefan Schmiedl EDV-Beratung Schmiedl, Berghangstr. 5, 93413 Cham Büro: +49 (0) 9971 9966 989, Mobil: +49 (0) 160 9981 6278 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 13:57 ` Stefan Schmiedl @ 2020-09-20 15:42 ` Zelphir Kaltstahl 0 siblings, 0 replies; 13+ messages in thread From: Zelphir Kaltstahl @ 2020-09-20 15:42 UTC (permalink / raw) To: Stefan Schmiedl; +Cc: guile-user Hello Stefan! Thank you for your explanation as well! On 9/20/20 3:57 PM, Stefan Schmiedl wrote: > Let's have a little shop talk with guile: > > $ guile-3.0 > GNU Guile 3.0.4-dirty > scheme@(guile-user)> (eqv? "a" "a") > $1 = #t > > Hypothesis: > guile's reader recognizes that the contents of both string literals > are the same and feeds the same string to the calling function. > > Check: > If that were the case, the two strings should not only be eqv? but > also eq? > > scheme@(guile-user)> (eq? "a" "a") > $2 = #t > > To see a different behaviour we need to avoid these literals and replace > them by values not built while reading but while executing the code: > > scheme@(guile-user)> (equal? (list->string (list #\a)) (list->string (list #\a))) > $3 = #t > > Now we compare two different string values which happen to end up with > identical content. And, behold: They are neither eqv? nor eq?. > > scheme@(guile-user)> (eqv? (list->string (list #\a)) (list->string (list #\a))) > $4 = #f > scheme@(guile-user)> (eq? (list->string (list #\a)) (list->string (list #\a))) > $5 = #f > > > Now let's see if that is consistent with the standard: > > According to r5rs, section 6.1 "Equivalence predicates": > > The eqv? procedure returns #t if: > ... > * obj1 and obj2 are pairs, vectors, or strings that denote > the same locations in the store (section 3.4). > > So we have learned > * that guile's reader reuses "store locations" for > strings of identical content I even learned a little bit about store locations and that a "store" exist as a concept in the implementation of Scheme and GNU Guile ; ) > * that eqv? is not the right predicate for content based string comparison I see! Thanks! > HTH > s. > > "Zelphir Kaltstahl" <zelphirkaltstahl@posteo.de>, 20.09.2020, 15:09: > >> And I've noticed something more about equality stuff in the context of >> tests: >> >> ~~~~ >> (eqv? "a" "a") >> $3 = #t >> >> ;; but >> >> (define char->>string >> (λ (c) >> (list->string >> (list c)))) >> >> (import >> ;; unit tests >> (srfi srfi-64)) >> (test-begin "string-utils-test") >> >> (test-group >> "char-to-string-test" >> >> (test-eqv "char->string converts a character to a string" >> "a" >> (char->string #\a))) >> >> (test-end "string-utils-test") >> >> %%%% Starting test string-utils-test (Writing full log to "string-utils-test.log") >> $2 = ("string-utils-test") >> :19: FAIL char->>string converts a character to a string >> # of unexpected failures 1 >> ~~~~ >> >> So while (eqv? ...) gives the correct (?) result, the test procedure >> (test-eqv ...) which seems to indicate using (eqv? ...) via its name >> does not think of the two strings as equivalent. >> >> >> On 20.09.20 14:19, Zelphir Kaltstahl wrote: >>> Sorry, I misclicked "send" when I wanted to further edit my e-mail ... >>> >>> My Guile version is: >>> >>> ~~~~ >>> (version) >>> $6 = "3.0.4" >>> ~~~~ >>> >>> On 20.09.20 14:16, Zelphir Kaltstahl wrote: >>>> Hello Guile users, >>>> >>>> I just noticed something weird about eq?. >>>> >>>> My Guile version is: >>>> >>>> >>>> I get the different results, depending on whether I define some >>>> bindings in a let or using define: >>>> >>>> (In Emacs Geiser:) >>>> >>>> ~~~~ >>>> (define x '(10 9)) >>>> (define y '(10 9)) >>>> (eq? x y) >>>> $2 = #f >>>> >>>> (let ([x '(10 9)] >>>> [y '(10 9)]) >>>> (eq? x y)) >>>> $3 = #t >>>> ~~~~ >>>> >>>> Is this intentional or a bug? >>>> >>>> I first noticed something strange when writing the following code: >>>> >>>> ~~~~DEFINITION~~~~ >>>> (define make-multiple-list-remover >>>> (λ (equal-proc) >>>> (λ (lst unwanted) >>>> (let loop ([remaining-list lst]) >>>> (cond >>>> [(null? remaining-list) >>>> '()] >>>> [(equal-proc (car remaining-list) unwanted) >>>> (loop (cdr remaining-list))] >>>> [else >>>> (cons (car remaining-list) >>>> (loop (cdr remaining-list)))]))))) >>>> ~~~~ >>>> >>>> ~~~~TEST~~~~ >>>> (let ([a '(9 10)] >>>> [b '(9 10)]) >>>> (test-equal "make-multiple-list-remover-03" >>>> `(1 2 (3) (4) ,a) >>>> ((make-multiple-list-remover eq?) >>>> `(a b (c) (d) ,a) b))) >>>> ~~~~ >>>> >>>> I was wondering, why the test fails. I think (eq? ...) should not be >>>> able to see the equivalence of both lists a and b, just like when >>>> defined using (define ...). >>>> >>>> I can also run it in the REPL and see the difference: >>>> >>>> ~~~~ >>>> (define a '(9 10)) >>>> (define b '(9 10)) >>>> ((make-multiple-list-remover eq?) >>>> `(a b (c) (d) ,a) b) >>>> $4 = (a b (c) (d) (9 10)) >>>> >>>> (let ([a '(9 10)] >>>> [b '(9 10)]) >>>> ((make-multiple-list-remover eq?) >>>> `(a b (c) (d) ,a) b)) >>>> $5 = (a b (c) (d)) >>>> ~~~~ >>>> >>>> Somehow the bindings of let seem to be different from the bindings >>>> created using define. What about using define inside let? >>>> >>>> ~~~~ >>>> >>>> ~~~~ >>>> -- >>>> repositories: https://notabug.org/ZelphirKaltstahl >>> Somehow the bindings of let seem to be different from the bindings >>> created using define. What about using define inside let? >>> >>> ~~~~ >>> (let ([unrelated 'bla]) >>> (define a '(9 10)) >>> (define b '(9 10)) >>> ((make-multiple-list-remover eq?) >>> `(a b (c) (d) ,a) b)) >>> $7 = (a b (c) (d)) >>> ~~~~ >>> >>> So there the define usage also differs from when I use define on the top >>> level. Perhaps that is the difference? On which level the bindings are >>> defined? >>> >>> Regards, >>> Zelphir >>> > > -- > Stefan Schmiedl > EDV-Beratung Schmiedl, Berghangstr. 5, 93413 Cham > Büro: +49 (0) 9971 9966 989, Mobil: +49 (0) 160 9981 6278 Best regards, Zelphir ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Surprising behavior of eq? 2020-09-20 12:16 Surprising behavior of eq? Zelphir Kaltstahl 2020-09-20 12:19 ` Zelphir Kaltstahl @ 2020-09-20 17:26 ` Taylan Kammer 1 sibling, 0 replies; 13+ messages in thread From: Taylan Kammer @ 2020-09-20 17:26 UTC (permalink / raw) To: Zelphir Kaltstahl, Guile User Others already mentioned 'equal?' as the correct predicate for testing structural content equality. It works not only for strings but also arbitrarily nested structures, for instance: (define a (list 'a 9871239876234 "foo" (vector #\a #\b #\c))) (define b '(a 9871239876234 (string #\f #\o #\o) #(#\a #\b #\c))) (equal? a b) ;=> #t (define c "foo") (define d 1234) (equal? c d) ;=> #f (obviously) But if you know that two variables both reference a string object, there's a more appropriate predicate which explicitly tests for string equality: 'string=?' (define a "foo") (define b (string #\f #\o #\o)) (string=? a b) ;=> #t (define c "foo") (define d 1234) (string=? c d) ;=> ERROR: wrong type argument 1234 passed to string=? Using 'string=?' instead of 'equal?' has a few small advantages in this case: - It makes it obvious to the reader of the code that two variables are both supposed to reference a string. - If due to some strange mistake one or both of the variables end up referencing an object that is not a string, the 'string=?' call will immediately raise an exception, which is probably better than it just returning #f and letting the code continue to run, because the code will probably crash at a later point anyway due to the object with the wrong type. (It's best for code to crash as soon as possible when an error like that happens, so you can find the root cause easily.) - Lastly, 'string=?' probably has a tiny performance advantage, though that's probably not important here. (If you experience performance issues with your code, you should benchmark it to see where the actual issue is. I'm just mentioning this for completeness' sake.) Of course if your variables may contain different types of values like lists and vectors and not just strings, you should indeed use 'equal?'. - Taylan ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2020-09-20 21:42 UTC | newest] Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-09-20 12:16 Surprising behavior of eq? Zelphir Kaltstahl 2020-09-20 12:19 ` Zelphir Kaltstahl 2020-09-20 12:58 ` Christopher Lemmer Webber 2020-09-20 13:09 ` Zelphir Kaltstahl 2020-09-20 13:52 ` John Cowan 2020-09-20 15:37 ` Zelphir Kaltstahl 2020-09-20 16:18 ` tomas 2020-09-20 17:05 ` John Cowan 2020-09-20 20:51 ` Linus Björnstam 2020-09-20 21:42 ` John Cowan 2020-09-20 13:57 ` Stefan Schmiedl 2020-09-20 15:42 ` Zelphir Kaltstahl 2020-09-20 17:26 ` Taylan Kammer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).