cisco / ChezScheme

Chez Scheme
Apache License 2.0
6.99k stars 987 forks source link

Unexpected result using conditional procedure and set! #857

Closed tomnor closed 4 months ago

tomnor commented 4 months ago

Unexpected result using conditional procedure and set!

Here is some strange piece of code:

;; pm1.scm

(define thing 8)

(define (plusminus)
  (cond
   ((< thing 10)
    (set! thing (+ thing 1))
    ((if (even? thing) + -) 1 (plusminus)))
   (else
    thing)))

(display "(plusminus) --> ")
(display (plusminus)) (newline)

Trying to walk through this manually to see what to expect:

;; (plusminus)
;; (- 1 (plusminus))
;; (- 1 (+ 1 (plusminus)))
;; (- 1 (+ 1 thing))                thing should be 10
;; (- 1 (+ 1 10)) --> -10
$ chez --version
10.0.0
$ chez --script pm1.scm
(plusminus) --> 12
$ guile pm1.scm
(plusminus) --> -10

Changing the conditional procedure selection (+ or -) to make explicit calls to the procedures (plus/minus) gives the result I would expect:

;; pm2.scm

(define thing 8)

(define (plusminus)
  (cond
   ((< thing 10)
    (set! thing (+ thing 1))
    (if (even? thing)
        (+ 1 (plusminus))
        (- 1 (plusminus))))
   (else
    thing)))

(display "(plusminus) --> ")
(display (plusminus)) (newline)
$ chez --script pm2.scm
(plusminus) --> -10

The problem can probably be reproduced in some simpler way but I couldn't figure out how.

What do you think, should the result be -10 for both pm1.scm and pm2.scm?

The chez binary used for test was built from a checkout of the commit tagged with v10.0.0 (253230f7)

mflatt commented 4 months ago

The issue here is unspecified evaluation order for parts of a function-call expression.

When you write ((if (even? thing) + -) 1 (plusminus)), then (if (even? thing?) + -) might get evaluated first, or (plusminus) might get evaluated first. If (plusminus) is first, the result ends up being 12.

Try these variants, which make evaluation order explicit using let:

    (let ([op (if (even? thing) + -)])
      (op 1 (plusminus)))
    (let ([v (plusminus)])
      ((if (even? thing) + -) 1 v))
tomnor commented 4 months ago

I see it now, very good insight for me. Thanks. It was confusing with different results with different implementations. For what it's worth, MIT Scheme produced the same result as Chez.

Necessary to be careful with evaluations when using assignments...