cisco/ChezScheme

Unexpected result using conditional procedure and set!

Closed this issue · 2 comments

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)

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))

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...