From: Tunc Simsek
Subject: Scoping
Date: 
Message-ID: <Pine.SOL.4.10.10006300113370.12012-100000@tudor.EECS.Berkeley.EDU>
Regards,

I may have asked a similar question before.  This relates
to scoping and special variables.

(defvar i 'foo)

(defun test (a)
  (declare (type (simple-array fixnum (*)) a))
  (declare (optimize (speed 3) (space 0) (safety 1)))
   (dotimes (i 10)
     (declare (type fixnum i))
       (setf (aref a i) i)))


Try compiling this and you get 7 notes (on type uncertainity)
with CMUCL on Solaris or Linux.
Either the special i is confusing the compiler, or there is
a documented mistake in this code.

Any help would be appreciated,
Thanks,
Tunc

From: Tim Bradshaw
Subject: Re: Scoping
Date: 
Message-ID: <ey3n1k3zcrg.fsf@cley.com>
* Tunc Simsek wrote:
> Try compiling this and you get 7 notes (on type uncertainity)
> with CMUCL on Solaris or Linux.
> Either the special i is confusing the compiler, or there is
> a documented mistake in this code.

Since it doesn't warn if I is not declared special, I think the answer
to this is fairly clear...

--tim
From: David Bakhash
Subject: Re: Scoping
Date: 
Message-ID: <c29n1k3b237.fsf@nerd-xing.mit.edu>
Tunc Simsek <······@tudor.EECS.Berkeley.EDU> writes:

> Try compiling this and you get 7 notes (on type uncertainity)
> with CMUCL on Solaris or Linux.
> Either the special i is confusing the compiler, or there is
> a documented mistake in this code.

I'm guessing that that shouldn't even be a warning.  The expansion for
DOTIMES should probably use GENSYM or whatever.  The same code in CLISP
yields:

> (defvar i 'foo)
I
> (defun test (a)
  (declare (type (simple-array fixnum (*)) a))
  (declare (optimize (speed 3) (space 0) (safety 1)))
   (dotimes (i 10)
     (declare (type fixnum i))
       (setf (aref a i) i)))

TEST
> (compile 'test)
TEST
> (setq my-array (make-array 10 :element-type 'fixnum :initial-element 0))
#(0 0 0 0 0 0 0 0 0 0)
> (test my-array)
NIL
> 

i.e. no warnings.  Something's wrong there with CMUCL I think.

dave
From: Tim Moore
Subject: Re: Scoping
Date: 
Message-ID: <8jij1a$n7v$0@216.39.145.192>
On 30 Jun 2000, David Bakhash wrote:
> Tunc Simsek <······@tudor.EECS.Berkeley.EDU> writes:
> 
> > Try compiling this and you get 7 notes (on type uncertainity)
> > with CMUCL on Solaris or Linux.
> > Either the special i is confusing the compiler, or there is
> > a documented mistake in this code.
> I'm guessing that that shouldn't even be a warning.  The expansion for
> DOTIMES should probably use GENSYM or whatever.  The same code in CLISP
> yields:

It doesn't emit warnings, it emits notes.  The CMUCL compiler gets very
vocal when it can't transform a function call to a more specific or
inlined call:

In: DEFUN TEST
  (DOTIMES (I 10) (DECLARE (TYPE FIXNUM I)) (SETF (AREF A I) I))
--> DO BLOCK LET TAGBODY UNLESS COND IF NOT IF >= IF 
==>
  (< I 10)
Note: Unable to optimize due to type uncertainty:
      The first argument is a REAL, not a FLOAT.
Note: Unable to optimize due to type uncertainty:
      The first argument is a REAL, not a INTEGER.

etc., etc.

> > (defvar i 'foo)
> I
> > (defun test (a)
>   (declare (type (simple-array fixnum (*)) a))
>   (declare (optimize (speed 3) (space 0) (safety 1)))
>    (dotimes (i 10)
>      (declare (type fixnum i))
>        (setf (aref a i) i)))

At first glance, the problem comes about because the references to i get
transformed to (symbol-value 'i).  CMUCL "knows" that that symbol-value
can return a value of type t; it doesn't propagate knowledge of the type
of i through the symbol-value call.

> i.e. no warnings.  Something's wrong there with CMUCL I think.

Something very minorly wrong, maybe.  Does CLISP optimize this code?

Tim
From: Raymond Toy
Subject: Re: Scoping
Date: 
Message-ID: <4naeg3awrl.fsf@rtp.ericsson.se>
>>>>> "Tim" == Tim Moore <·····@herschel.bricoworks.com> writes:


    >> > (defvar i 'foo)
    >> I
    >> > (defun test (a)
    >> (declare (type (simple-array fixnum (*)) a))
    >> (declare (optimize (speed 3) (space 0) (safety 1)))
    >> (dotimes (i 10)
    >> (declare (type fixnum i))
    >> (setf (aref a i) i)))

    Tim> At first glance, the problem comes about because the references to i get
    Tim> transformed to (symbol-value 'i).  CMUCL "knows" that that symbol-value
    Tim> can return a value of type t; it doesn't propagate knowledge of the type
    Tim> of i through the symbol-value call.

How did you come to this conclusion?  When I macroexpand the dotimes,
I get:

(BLOCK NIL
  (LET ((I 0))
    (DECLARE (TYPE UNSIGNED-BYTE I))
    (DECLARE (TYPE FIXNUM I))
    (TAGBODY
      (GO #:G18437)
     #:G18436
      (SETF (AREF A I) I)
      (PSETQ I (1+ I))
     #:G18437
      (UNLESS (>= I 10) (GO #:G18436))
      (RETURN-FROM NIL (PROGN NIL))))

I always thought the notes came from the fact that I is defvar'ed
without any declaration of the type, and this code binds I.  I guess
the compiler is being conservative here in case the body of the loop
rebinds I to something weird?

Of course, with the declaration and the given body, it seems the
compiler could actually determine I will always be a fixnum (except
for (1+ I), which might not be), so CMUCL shouldn't emit any notes at
all.  

Without the defvar, things should look very nice.  Or if you add
(declaim (type fixnum i)) after the defvar (after changing the
initialization), there is exactly one note about checking (1+ i) is a
fixnum.

    Tim> Something very minorly wrong, maybe.  Does CLISP optimize this code?

Macroexpansion of the dotimes returns almost exactly the same thing as
CMUCL.  I don't think Clisp does anything special.

Ray
From: Tim Moore
Subject: Re: Scoping
Date: 
Message-ID: <8jiqhq$4m5$0@216.39.145.192>
On 30 Jun 2000, Raymond Toy wrote:

>     Tim> At first glance, the problem comes about because the references to i get
>     Tim> transformed to (symbol-value 'i).  CMUCL "knows" that that symbol-value
>     Tim> can return a value of type t; it doesn't propagate knowledge of the type
>     Tim> of i through the symbol-value call.
> 
> How did you come to this conclusion?  When I macroexpand the dotimes,
> I get:

From reading the code and trace file a little too quickly.  I assumed that
the references to i were being converted to (symbol-value ') early, but
they're not;  the compiler ought to see the type declaration for the refs
to i.  Hmm.

> 
> (BLOCK NIL
>   (LET ((I 0))
>     (DECLARE (TYPE UNSIGNED-BYTE I))
>     (DECLARE (TYPE FIXNUM I))
>     (TAGBODY
>       (GO #:G18437)
>      #:G18436
>       (SETF (AREF A I) I)
>       (PSETQ I (1+ I))
>      #:G18437
>       (UNLESS (>= I 10) (GO #:G18436))
>       (RETURN-FROM NIL (PROGN NIL))))
> 
> I always thought the notes came from the fact that I is defvar'ed
> without any declaration of the type, and this code binds I.  I guess
> the compiler is being conservative here in case the body of the loop
> rebinds I to something weird?
Maybe, but the type declaration should hold outside of any such binding :/

Tim
From: Tunc Simsek
Subject: Re: Scoping
Date: 
Message-ID: <395D037C.80525062@robotics.eecs.berkeley.edu>
What is your conclusion? What should be the right way to use dotimes?

1. Do I need the (declare (fixnum i)) ?
2. Should the compiler really be giving me notes?
3. Should I take attention to those notes?

Thanks,
Tunc

The fact is that, having I as a loop counter is unavoidable. Also,
setting I globally will eventually happen.  So, suppose I don't 
defvar the special i.  Then, I compile, everything is o.k., but
later I defvar the special i ---> will this cause a problem?



Raymond Toy wrote:
> 
> >>>>> "Tim" == Tim Moore <·····@herschel.bricoworks.com> writes:
> 
>     >> > (defvar i 'foo)
>     >> I
>     >> > (defun test (a)
>     >> (declare (type (simple-array fixnum (*)) a))
>     >> (declare (optimize (speed 3) (space 0) (safety 1)))
>     >> (dotimes (i 10)
>     >> (declare (type fixnum i))
>     >> (setf (aref a i) i)))
> 
>     Tim> At first glance, the problem comes about because the references to i get
>     Tim> transformed to (symbol-value 'i).  CMUCL "knows" that that symbol-value
>     Tim> can return a value of type t; it doesn't propagate knowledge of the type
>     Tim> of i through the symbol-value call.
> 
> How did you come to this conclusion?  When I macroexpand the dotimes,
> I get:
> 
> (BLOCK NIL
>   (LET ((I 0))
>     (DECLARE (TYPE UNSIGNED-BYTE I))
>     (DECLARE (TYPE FIXNUM I))
>     (TAGBODY
>       (GO #:G18437)
>      #:G18436
>       (SETF (AREF A I) I)
>       (PSETQ I (1+ I))
>      #:G18437
>       (UNLESS (>= I 10) (GO #:G18436))
>       (RETURN-FROM NIL (PROGN NIL))))
> 
> I always thought the notes came from the fact that I is defvar'ed
> without any declaration of the type, and this code binds I.  I guess
> the compiler is being conservative here in case the body of the loop
> rebinds I to something weird?
> 
> Of course, with the declaration and the given body, it seems the
> compiler could actually determine I will always be a fixnum (except
> for (1+ I), which might not be), so CMUCL shouldn't emit any notes at
> all.
> 
> Without the defvar, things should look very nice.  Or if you add
> (declaim (type fixnum i)) after the defvar (after changing the
> initialization), there is exactly one note about checking (1+ i) is a
> fixnum.
> 
>     Tim> Something very minorly wrong, maybe.  Does CLISP optimize this code?
> 
> Macroexpansion of the dotimes returns almost exactly the same thing as
> CMUCL.  I don't think Clisp does anything special.
> 
> Ray
From: Raymond Toy
Subject: Re: Scoping
Date: 
Message-ID: <4n4s6ac1dm.fsf@rtp.ericsson.se>
>>>>> "Tunc" == Tunc Simsek <······@robotics.eecs.berkeley.edu> writes:

    Tunc> What is your conclusion? What should be the right way to use dotimes?

    Tunc> 1. Do I need the (declare (fixnum i)) ?

If I is a fixnum, it will help the compiler generate better code. (At
least without the defvar.)

    Tunc> 2. Should the compiler really be giving me notes?

I think so, but I'm not sure.

    Tunc> 3. Should I take attention to those notes?

You should at least look at them and decide whether they matter to you
or not.

    Tunc> The fact is that, having I as a loop counter is unavoidable. Also,
    Tunc> setting I globally will eventually happen.  So, suppose I don't 
    Tunc> defvar the special i.  Then, I compile, everything is o.k., but
    Tunc> later I defvar the special i ---> will this cause a problem?

I don't think so.  However, you'll have problems if you should
recompile the code again after the defvar.

I don't understand why you would want to do this.  Special variables
are special, so you need to pay attention.

Ray
From: Tim Bradshaw
Subject: Re: Scoping
Date: 
Message-ID: <ey33dluzwuc.fsf@cley.com>
* Tunc Simsek wrote:

> The fact is that, having I as a loop counter is unavoidable. Also,
> setting I globally will eventually happen.  So, suppose I don't 
> defvar the special i.  Then, I compile, everything is o.k., but
> later I defvar the special i ---> will this cause a problem?

No.  But there's a reason why people use stars around special
variables...

I can feel a revival of the `special syntax for special variables'
thread coming on.  This is fairly long-standing witness this fragment
from an article posted on 5-feb-1990:

In article <···@forsight.Jpl.Nasa.Gov> ···@robotics.Jpl.Nasa.Gov (Erann Gat) writes:
 >           However, the way things stand, one careless mistake or
 >ignorant user can require a LONG time to fix.  (One day long ago I
 >typed (defvar x 1) as part of a quick experiment on a TI Explorer
 >and for the next few days no one could understand why their code
 >suddenly didn't work.  Then someone rebooted the machine and all the
 >problems mysteriously vanished.)

--tim
From: Tim Moore
Subject: Re: Scoping
Date: 
Message-ID: <8jj5t2$pr9$0@216.39.145.192>
On Fri, 30 Jun 2000, Tunc Simsek wrote:

> What is your conclusion? What should be the right way to use dotimes?
> 
> 1. Do I need the (declare (fixnum i)) ?
No.  You hardly ever need to declare anything in Common Lisp, with the
exception of special.

If you care about the speed of this chunk of code, you might want type
declaration.  "fixnum" is traditional, though not particularly portable;
do you know the fixnum range offhand in CMUCL?  If you know the range that
a variable will take on, you should declare that directly, like (declare
type (integer 0 11) i).  Quality compilers will decide whether or not that
type is in fact a member of fixnum.

In this case, assuming i isn't special, you don't need the declaration
because CMUCL can derive the fixnum type from the constant count specified
in dotimes.

> 2. Should the compiler really be giving me notes?

*Shrug*  Why not?  If they're really annoying you can figure out how to
direct them to a file or not see them at all, I think.  If you're trying
to optimize your code they can be very helpful.

> The fact is that, having I as a loop counter is unavoidable. Also,
> setting I globally will eventually happen.  So, suppose I don't 
> defvar the special i.  Then, I compile, everything is o.k., but
> later I defvar the special i ---> will this cause a problem?
> 

Why does the counter variable in your dotimes form have to be a global
variable?

Tim
From: Tunc Simsek
Subject: Re: Scoping
Date: 
Message-ID: <395D42D2.4B53C8D2@robotics.eecs.berkeley.edu>
Tim Moore wrote:
> 
> On Fri, 30 Jun 2000, Tunc Simsek wrote:
> 
> > What is your conclusion? What should be the right way to use dotimes?
> >
> > 1. Do I need the (declare (fixnum i)) ?
> No.  You hardly ever need to declare anything in Common Lisp, with the
> exception of special.
> 
> If you care about the speed of this chunk of code, you might want type
> declaration.  "fixnum" is traditional, though not particularly portable;
> do you know the fixnum range offhand in CMUCL?  If you know the range that
> a variable will take on, you should declare that directly, like (declare
> type (integer 0 11) i).  Quality compilers will decide whether or not that
> type is in fact a member of fixnum.
> 
> In this case, assuming i isn't special, you don't need the declaration
> because CMUCL can derive the fixnum type from the constant count specified
> in dotimes.
> 
> > 2. Should the compiler really be giving me notes?
> 
> *Shrug*  Why not?  If they're really annoying you can figure out how to
> direct them to a file or not see them at all, I think.  If you're trying
> to optimize your code they can be very helpful.
> 

No, I'm not annoyed, but just worried of future problems if I ignore
them.
I'll try to get rid of them.

> > The fact is that, having I as a loop counter is unavoidable. Also,
> > setting I globally will eventually happen.  So, suppose I don't
> > defvar the special i.  Then, I compile, everything is o.k., but
> > later I defvar the special i ---> will this cause a problem?
> >
> 
> Why does the counter variable in your dotimes form have to be a global
> variable?

It doesn't.  It happens by accident, but does happen.

Thanks, I get the idea.  I think, that I'll try to make sure to compile
the code in a clean environment (no specials), and see if any problems
show up from there on.


> 
> Tim
From: Tim Bradshaw
Subject: Re: Scoping
Date: 
Message-ID: <ey366qqzzku.fsf@cley.com>
* Raymond Toy wrote:

> I always thought the notes came from the fact that I is defvar'ed
> without any declaration of the type, and this code binds I.  I guess
> the compiler is being conservative here in case the body of the loop
> rebinds I to something weird?

I've assumed that you're doomed with specials, because of things like:

    (defvar *i* 1)

    (defun doit ()
      (let ((*i* 10))
	(= *i* (progn (frob-i) *i*)))

    (defun frob-i ()
      (setf *i* 100))

Obviously there are some nice cases that you could spot -- for
instance if there are no function calls in the area where *I* is bound
you might have a chance of making some assumptions about it.  But why
bother, really?  There must be better things to spend time trying to
generate good code for.

The case you probably would want to care about is where there's a
global declaration for the special, because you might want to compile
good code for things like (* foo *my-parameter*).

--tim