Subject: redefinition of +

From: Ian Price <[email-masked]>
Date: Mon, 04 Mar 2013 00:42:12 +0000

Hi guys,
On #guile, euiuer (CCed) reported this, though he was to shy to report
this himself. In guile 1.8.7

<euiuer> (define (foo) (+ 1 1))
<euiuer> (define (+ a b) (- a b))
<euiuer> (display (foo))
<euiuer> (display (+ 1 1))
<euiuer> it evails like 0 and 0.
<euiuer> but..
<euiuer> (define (foo) (+ 1 1))
<euiuer> (display (foo))
<euiuer> (define (+ a b) (- a b))
<euiuer> (display (foo))
<euiuer> (display (+ 1 1))
<euiuer> it evails like 2 2 0
<euiuer> it is kind of odd.

He confirms he gets these when he runs these from a script.

I get the same on my 1.8.8 install, both at the repl and from a script.

Since it evaluates correct if we run (bar) _after_ redefining + I think
it's a safe bet to assume that 1.8 cached the reference to +, but not
having been around for 1.8, this is a conjecture only.

Now, 1.8 is the old series, how about 2? Running a recent master
(9b977c836bf147d386944c401113aba32776fa68)[0].

>From the repl:
scheme@(guile−user)> (define (foo) (+ 1 1))
scheme@(guile−user)> (define (+ a b) (- a b))
scheme@(guile−user)> (foo)
$2 = 2
scheme@(guile−user)> (+ 1 1)
$3 = 0

and

scheme@(guile−user)> (define (foo) (+ 1 1))
scheme@(guile−user)> (foo)
$2 = 2
scheme@(guile−user)> (define (+ a b) (- a b))
scheme@(guile−user)> (foo)
$3 = 2
scheme@(guile−user)> (+ 1 1)
$4 = 0

>From a script
$ guile -q -s /tmp/file1.scm
22
$ guile -q -s /tmp/file2.scm
222

This behaviour can be "blamed" on guile 2's more aggressive
optimisation. Indeed, 

scheme@(guile−user)> ,disassemble foo
Disassembly of #<procedure foo ()>:

   0    (assert−nargs−ee/locals 0)      ;; 0 args, 0 locals
   2    (make−int8 2)                   ;; 2                  at (unknown file):5:14
   4    (return)      

is pretty much what we want usually. And I'm inclined to say NOTABUG for
the repl when optimisation is turned on. However, in a script, this is a
bug IMO, since we shouldn't really be optimising + if our top-level
binding for + is not the builtin one, and we can certainly detect a
redefinition of + within a file.

Just to be sure, I tried turning off cse and peal, but ran into a
different optimisation

scheme@(guile−user)> ,option compile-options (#:partial-eval? #f #:cse? #f)
scheme@(guile−user)> ,option compile-options
(#:partial−eval? #f #:cse? #f)
scheme@(guile−user)> (foo)
$2 = 2
scheme@(guile−user)> (+ )
$3 = 0
scheme@(guile−user)> (define (+ a b) (- a b))
scheme@(guile−user)> (foo)
$4 = 2
scheme@(guile−user)> (+ 1 1)
$5 = 0

Have you guessed what it was?

scheme@(guile−user)> ,disassemble foo
Disassembly of #<procedure foo ()>:

   0    (assert−nargs−ee/locals 0)      ;; 0 args, 0 locals
   2    (make−int8:1)                   ;; 1
   3    (add1)                                                at (unknown file):44:14
   4    (return)                        

So, you can't win on this one :)

[0] I have not got a stable-2.0 install at the moment to compare, but I
suspect it will be similar.

-- 
Ian Price -- shift-reset.com

"Programming is like pinball. The reward for doing it well is
the opportunity to do it again" - from "The Wizardy Compiled"