From: Wolfhard Buß
Subject: dolist type declaration
Date: 
Message-ID: <m3y93w7e09.fsf@buss-14250.user.cis.dfn.de>
Unfortunately

 (dolist (i <list-of-type type-spec>...)
   (declare (type-spec i))...)

is *not* conforming CL, though implementations are free to
introduce new declaration identifiers such as elm-type e.g.

Now one can write

 (dolist (i <list-of-type type-spec>...)
   (declare (elm-type type-spec))...)

and our new dolist implementation expands this into something like

 (dolist (i <list-of-type type-spec>...)
   ...
   (let ((i i)
     (declare (type-spec i))...))...)

Costs:

 (dolist (<type-spec> list)
   (declare (elm-type <type-spec>))...)

The new implementation of dolist declares the elements of the list to
be of type <type-spec> not the iteration variable <type-spec> to be of
type elm-type. Free of charge!


 (dolist (<not-type-spec> list)
   (declare (elm-type <type-spec>))...)

does not declare the var <type-spec> to be of type elm-type. In this
rare? case programs will pay the price. 


Since implementations are free to define undefined behavior, they
could exclude the result form of dolist from the scope of a type
declaration for the iteration variable. (They will *not* exclude a
special declaration:) This might be the low cost possibility.


However, impatient fellow Lispnik will possibly not wait for a new
implementation of dolisp, and will use iterate instead:

 (iter (for elm in '(1/2 2/3 3/4))
       (declare (ratio elm))
       ...)


Btw, what's the history of dolist? 


-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)

From: rif
Subject: Re: dolist type declaration
Date: 
Message-ID: <wj0fzq4pmoe.fsf@five-percent-nation.mit.edu>
·····@gmx.net (Wolfhard Bu�) writes:

> Unfortunately
> 
>  (dolist (i <list-of-type type-spec>...)
>    (declare (type-spec i))...)
> 
> is *not* conforming CL, though implementations are free to
> introduce new declaration identifiers such as elm-type e.g.

Why is this not conforming?  I'm not saying it is, I'm just trying to
understand.

rif
From: Wolfhard Buß
Subject: Re: dolist type declaration
Date: 
Message-ID: <m3r89o7clc.fsf@buss-14250.user.cis.dfn.de>
> ·····@gmx.net (Wolfhard Bu�) writes:
>
>  (dolist (i <list-of-type type-spec>...)
>    (declare (type-spec i))...)
> 
> is *not* conforming CL...

rif <···@mit.edu> writes: 
>
> Why is this not conforming?

Oops. Intended was:

 (dolist (i <list-of-type type-spec>...)
   (declare (type-spec i))...)

is in general *not* conforming CL...

Not conforming, when nil is not included in type-spec. What makes type
declarations for the dolist iteration variable pretty useless.

-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)
From: rif
Subject: Re: dolist type declaration
Date: 
Message-ID: <wj07kbgjws8.fsf@five-percent-nation.mit.edu>
> Oops. Intended was:
> 
>  (dolist (i <list-of-type type-spec>...)
>    (declare (type-spec i))...)
> 
> is in general *not* conforming CL...
> 
> Not conforming, when nil is not included in type-spec. What makes type
> declarations for the dolist iteration variable pretty useless.

I stil don't understand why it's not conforming.  You're saying
specifically that

(dolist (i list-of-fixnums)
  (declare (type fixnum i))
  (princ i))

is not conforming?

rif
From: Wolfhard Buß
Subject: Re: dolist type declaration
Date: 
Message-ID: <m3isv076fa.fsf@buss-14250.user.cis.dfn.de>
rif <···@mit.edu> writes:
>
> You're saying specifically that
> 
> (dolist (i list-of-fixnums)
>   (declare (type fixnum i))
>   (princ i))
> 
> is not conforming?

Exactly. As far as I understand The Standard.

[CLHS 3.3.4 Declaration Scope] ... Some iteration forms include step,
end-test, or result subforms that are also included in the scope of
declarations that appear in the iteration form. Specifically, the
iteration forms and subforms involved are: ... 
dolist, dotimes: result-form ...

[CLHS 6.2 DOLIST] ... Then result-form is evaluated. ... At the time
result-form is processed, var is bound to nil. 

[CLHS 3.8 TYPE] ... 
2. During the execution of any setq of the declared variable within
the scope of the declaration, the consequences are undefined if the
newly assigned value of the declared variable is not of the declared
type. 

3. At the moment the scope of the declaration is entered, the
consequences are undefined if the value of the declared variable is
not of the declared type. 

And finally [CLHS 1.4.2] The consequences are undefined
... No conforming code may depend on the results or effects.


-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)
From: rif
Subject: Re: dolist type declaration
Date: 
Message-ID: <wj03cm4jqlc.fsf@five-percent-nation.mit.edu>
·····@gmx.net (Wolfhard Bu�) writes:

> rif <···@mit.edu> writes:
> >
> > You're saying specifically that
> > 
> > (dolist (i list-of-fixnums)
> >   (declare (type fixnum i))
> >   (princ i))
> > 
> > is not conforming?
> 
> Exactly. As far as I understand The Standard.
> 

OK, thanks for taking the time to explain, I understand what you're
saying now.  And similarly, fixtimes, my version of dotimes which
always declares the iteration variable to be a fixnum, is also not
conforming.  So what are the implications?

rif
From: Christophe Rhodes
Subject: Re: dolist type declaration
Date: 
Message-ID: <sqznocqr1l.fsf@lambda.jcn.srcf.net>
rif <···@mit.edu> writes:

> ·····@gmx.net (Wolfhard Bu�) writes:
> 
> > rif <···@mit.edu> writes:
> > >
> > > You're saying specifically that
> > > 
> > > (dolist (i list-of-fixnums)
> > >   (declare (type fixnum i))
> > >   (princ i))
> > > 
> > > is not conforming?
> > 
> > Exactly. As far as I understand The Standard.
> > 
> 
> OK, thanks for taking the time to explain, I understand what you're
> saying now.  And similarly, fixtimes, my version of dotimes which
> always declares the iteration variable to be a fixnum, is also not
> conforming.  So what are the implications?

That if you want conforming code without changing the spec, you have
to do
  (dolist (i list-of-fixnums)
    (let ((i i))
      (declare (type fixnum i))
      ...))
or
  (dolist (i list-of-fixnums)
    (locally
      (declare (type fixnum i))
      ...)).

Are there many examples of lists of fixnums around, in live code?

Cheers,

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: rif
Subject: Re: dolist type declaration
Date: 
Message-ID: <wj0d6l8pca4.fsf@five-percent-nation.mit.edu>
> > OK, thanks for taking the time to explain, I understand what you're
> > saying now.  And similarly, fixtimes, my version of dotimes which
> > always declares the iteration variable to be a fixnum, is also not
> > conforming.  So what are the implications?
> 
> That if you want conforming code without changing the spec, you have
> to do
>   (dolist (i list-of-fixnums)
>     (let ((i i))
>       (declare (type fixnum i))
>       ...))
> or
>   (dolist (i list-of-fixnums)
>     (locally
>       (declare (type fixnum i))
>       ...)).
> 
> Are there many examples of lists of fixnums around, in live code?
> 

I don't know about lists of fixnums, but I do dotimes and declare the
loop variable to be a fixnum all the time.  I guess my code is
non-conforming.  CMUCL seems to do what I expect.

Is there a good reason for the spec being this way, or is this just
some weird oversight?

rif
From: Thomas F. Burdick
Subject: Re: dolist type declaration
Date: 
Message-ID: <xcvr89odv90.fsf@fallingrocks.OCF.Berkeley.EDU>
rif <···@mit.edu> writes:

> > > OK, thanks for taking the time to explain, I understand what you're
> > > saying now.  And similarly, fixtimes, my version of dotimes which
> > > always declares the iteration variable to be a fixnum, is also not
> > > conforming.  So what are the implications?
> > 
> > That if you want conforming code without changing the spec, you have
> > to do
> >   (dolist (i list-of-fixnums)
> >     (let ((i i))
> >       (declare (type fixnum i))
> >       ...))
> > or
> >   (dolist (i list-of-fixnums)
> >     (locally
> >       (declare (type fixnum i))
> >       ...)).
> > 
> > Are there many examples of lists of fixnums around, in live code?
> > 
> 
> I don't know about lists of fixnums, but I do dotimes and declare the
> loop variable to be a fixnum all the time.  I guess my code is
> non-conforming.  CMUCL seems to do what I expect.

Christophe already explained why this works for dotimes, but the
reason why it works in CMUCL for dolist, in case you're curious, is
that the expansion of:

  (dolist (i '(1 2 3 4 5) i)
    (declare (fixnum i))
    (print i))

produces two bindings for I:

  (block nil
    (let ((#:list '(1 2 3 4 5)))
      (tagbody
        ...
        (let ((i (car #:list)))
          (declare (fixnum i))
          (print i))
        ...
        (return-from nil
          (let ((i nil))
            i)))))

Naturally, you can't rely on this outside of CMUCL, but that does
explain why a type-picky implementation like CMUCL lets you get away
with this.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Christophe Rhodes
Subject: Re: dolist type declaration
Date: 
Message-ID: <sqr89oqghx.fsf@lambda.jcn.srcf.net>
···@fallingrocks.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Naturally, you can't rely on this outside of CMUCL, but that does
> explain why a type-picky implementation like CMUCL lets you get away
> with this.

Actually, I have reason to believe that it won't let you get away with
it for evermore... so don't rely on it.

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Thomas F. Burdick
Subject: Re: dolist type declaration
Date: 
Message-ID: <xcvadgbmwze.fsf@apocalypse.OCF.Berkeley.EDU>
Christophe Rhodes <·····@cam.ac.uk> writes:

> ···@fallingrocks.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > Naturally, you can't rely on this outside of CMUCL, but that does
> > explain why a type-picky implementation like CMUCL lets you get away
> > with this.
> 
> Actually, I have reason to believe that it won't let you get away with
> it for evermore... so don't rely on it.

Not that I would make a habit of relying on it, but why?  I can't
really see any reason to change it, and I'm pretty sure it's
conforming.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Tim Bradshaw
Subject: Re: dolist type declaration
Date: 
Message-ID: <ey3vfyzh2be.fsf@cley.com>
* Christophe Rhodes wrote:
> Actually, I have reason to believe that it won't let you get away with
> it for evermore... so don't rely on it.

Why change it?  The current implementation (a) agrees with the spec,
and (b) works in the way people expect.  Why change it to something
that neither agrees with the spec nor works.

--tim
From: Christophe Rhodes
Subject: Re: dolist type declaration
Date: 
Message-ID: <sq3cm3qun6.fsf@lambda.jcn.srcf.net>
Tim Bradshaw <···@cley.com> writes:

> * Christophe Rhodes wrote:
> > Actually, I have reason to believe that it won't let you get away with
> > it for evermore... so don't rely on it.
> 
> Why change it?  The current implementation (a) agrees with the spec,
> and (b) works in the way people expect.  Why change it to something
> that neither agrees with the spec nor works.

Because it doesn't agree with the spec.  I thought we'd hashed this
out here already, but declarations are meant to apply to the binding
while the result form is executed as well as for the body.  It doesn't
matter so much for type declarations of the iteration variable, but it
does matter critically for special declarations.

Further, there is a conforming workaround for a revised implementation
if you do actually have a list of fixnums and you're iterating across
said list: simply rebind the iteration variable in the body, and then
declare its type.

Or are we talking at cross-purposes here?

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Tim Bradshaw
Subject: Re: dolist type declaration
Date: 
Message-ID: <ey3n0kbgxyn.fsf@cley.com>
* Christophe Rhodes wrote:

> Because it doesn't agree with the spec.  I thought we'd hashed this
> out here already, but declarations are meant to apply to the binding
> while the result form is executed as well as for the body.  It doesn't
> matter so much for type declarations of the iteration variable, but it
> does matter critically for special declarations.

So, what you mean is something like this:

(dotimes (i '(1 2 3) #'(lambda () i))
  (declare (special i)))

would return a closure which captures the lexical I established in the
result-form in the `rebind I in result form' version but return a
funcall which (likely) refers to an unbound variable in the
non-rebinding form.

I suppose a more realistic case would be some code in the result form
which uses I free and expects it to be a special.

OK, that's clearly a difference.  I can't see that the spec actually
implies this though.  It clearly does imply that the declaration scope
includes the result form, and that the iteration variable needs to be
still bound, but I don't think it says there can't be another variable
bound which shadows it.  Maybe this has been gone through in some
thread I ignored then.

If it clearly does say that then I think there are a couple of
reasonable solutions (the `make-the-user-rebind-it-by-hand-so it can
be declared sensibly, or make sure the type declaration allows NIL'
solutions are both hideous: why should the language force you through
those stupid hoops).

1. The spec should say  that in the result form the iteration variable
   is bound but to the last element of the list.  This is an
   incompatible change and not very good.

2. Implementations should rebind the variable to NIL, and the
   declarations which applied before should be inserted in the
   rebinding form, with any type declaration possibly suitably
   weakened (just wrap it with (or null ...)).

(2) seems to me much better.  I can't see a case where (other than the
issue about type, which is pretty implicit since the spec says it
will be NIL) where an application could tell the difference: in
particular any SPECIAL declarations will still be in effect (or will
again be in effect).

--tim
From: Christophe Rhodes
Subject: Re: dolist type declaration
Date: 
Message-ID: <sqwujfpbpc.fsf@lambda.jcn.srcf.net>
Tim Bradshaw <···@cley.com> writes:

> * Christophe Rhodes wrote:
> 
> > Because it doesn't agree with the spec.  I thought we'd hashed this
> > out here already, but declarations are meant to apply to the binding
> > while the result form is executed as well as for the body.  It doesn't
> > matter so much for type declarations of the iteration variable, but it
> > does matter critically for special declarations.
> 
> So, what you mean is something like this:
> 
> (dotimes (i '(1 2 3) #'(lambda () i))
>   (declare (special i)))
> [...]
> I suppose a more realistic case would be some code in the result form
> which uses I free and expects it to be a special.

Yes.  There was some discussion in a thread title "dolist": see
<··············@buss-14250.user.cis.dfn.de> and subsequent messages.

I ask again: are there examples of lists of fixnums, or somesuch, in
real code?  The reason I ask is that it seems slightly odd to me that
one would, in a situation where a declaration would make a difference
in execution speed, be using a list of same-typed objects.  But maybe
I just haven't seen an example, and this is actually a common idiom?

I have a certain amount more sympathy if you factor in the
declarations-are-assertions mode of CMUCL and friends; then I guess
it's slightly annoying to have to include the NULL type as well.  But,
to be honest, I don't consider rebinding (or LOCALLY, an equivalent
solution) to be so utterly hideous as to warrant discounting.  The
language provides the way to say two different things; you seem to be
saying that it's optimized for the uncommon case, which is a fair
complaint, but I wonder just how common the common case actually is.

Cheers,

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Thomas F. Burdick
Subject: Re: dolist type declaration
Date: 
Message-ID: <xcvadgargug.fsf@apocalypse.OCF.Berkeley.EDU>
Christophe Rhodes <·····@cam.ac.uk> writes:

> Tim Bradshaw <···@cley.com> writes:
> 
> > * Christophe Rhodes wrote:
> > 
> > > Because it doesn't agree with the spec.  I thought we'd hashed this
> > > out here already, but declarations are meant to apply to the binding
> > > while the result form is executed as well as for the body.  It doesn't
> > > matter so much for type declarations of the iteration variable, but it
> > > does matter critically for special declarations.
> > 
> > So, what you mean is something like this:
> > 
> > (dotimes (i '(1 2 3) #'(lambda () i))
> >   (declare (special i)))
> > [...]
> > I suppose a more realistic case would be some code in the result form
> > which uses I free and expects it to be a special.
> 
> Yes.  There was some discussion in a thread title "dolist": see
> <··············@buss-14250.user.cis.dfn.de> and subsequent messages.

(Huh, I guess I did miss that thread, and the discussion on cmucl-imp)

> I ask again: are there examples of lists of fixnums, or somesuch, in
> real code?  The reason I ask is that it seems slightly odd to me that
> one would, in a situation where a declaration would make a difference
> in execution speed, be using a list of same-typed objects.  But maybe
> I just haven't seen an example, and this is actually a common idiom?

I know that I've done this a few times.  One case where the elements
were double-floats, another where they were some type like (integer 1 x),

where X was important for not consing a ton.  I suppose I could just
wrap the body in a LOCALLY, but Python doesn't like things to be too
deeply nested, and that seems like an aweful waste for a dolist to
create three levels of local environments.

> I have a certain amount more sympathy if you factor in the
> declarations-are-assertions mode of CMUCL and friends; then I guess
> it's slightly annoying to have to include the NULL type as well.

Yeah, but in this case, I'd probably just write (the TYPE x) at the
top of the body...

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Christophe Rhodes
Subject: Re: dolist type declaration
Date: 
Message-ID: <sqbs0qotoc.fsf@lambda.jcn.srcf.net>
···@apocalypse.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Christophe Rhodes <·····@cam.ac.uk> writes:
> 
> > I ask again: are there examples of lists of fixnums, or somesuch, in
> > real code?  The reason I ask is that it seems slightly odd to me that
> > one would, in a situation where a declaration would make a difference
> > in execution speed, be using a list of same-typed objects.  But maybe
> > I just haven't seen an example, and this is actually a common idiom?
> 
> I know that I've done this a few times.  One case where the elements
> were double-floats, another where they were some type like (integer 1 x),
> where X was important for not consing a ton.  I suppose I could just
> wrap the body in a LOCALLY, but Python doesn't like things to be too
> deeply nested, and that seems like an aweful waste for a dolist to
> create three levels of local environments.

It doesn't like things being too deeply nested?  What was the issue?
Can you say more?

Cheers,

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Thomas F. Burdick
Subject: Re: dolist type declaration
Date: 
Message-ID: <xcv1y1lnoue.fsf@famine.OCF.Berkeley.EDU>
Christophe Rhodes <·····@cam.ac.uk> writes:

> ···@apocalypse.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > Christophe Rhodes <·····@cam.ac.uk> writes:
> > 
> > > I ask again: are there examples of lists of fixnums, or somesuch, in
> > > real code?  The reason I ask is that it seems slightly odd to me that
> > > one would, in a situation where a declaration would make a difference
> > > in execution speed, be using a list of same-typed objects.  But maybe
> > > I just haven't seen an example, and this is actually a common idiom?
> > 
> > I know that I've done this a few times.  One case where the elements
> > were double-floats, another where they were some type like (integer 1 x),
> > where X was important for not consing a ton.  I suppose I could just
> > wrap the body in a LOCALLY, but Python doesn't like things to be too
> > deeply nested, and that seems like an aweful waste for a dolist to
> > create three levels of local environments.
> 
> It doesn't like things being too deeply nested?  What was the issue?
> Can you say more?

At some point the compiler bails, and generates more naive code,
doesn't it?  I know I've seen this with code of mine that was deeply
nested.  Searching my email, I noticed that this was touched on in the
"sbcl merge" thread on cmucl-imp in mid-december.  EG, your message:
<·····················@cam.ac.uk>.  Maybe LOCALLY doesn't bother
Python here?  In my own code, I don't worry about this, except in the
few cases where I've gotten problems I could solve by splitting things
up -- but system macros should be held to a higher standard, which is
why I voiced concern.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Tim Bradshaw
Subject: Re: dolist type declaration
Date: 
Message-ID: <ey3heajgt73.fsf@cley.com>
* Christophe Rhodes wrote:

> I ask again: are there examples of lists of fixnums, or somesuch, in
> real code?  The reason I ask is that it seems slightly odd to me that
> one would, in a situation where a declaration would make a difference
> in execution speed, be using a list of same-typed objects.  But maybe
> I just haven't seen an example, and this is actually a common idiom?

Well, I'm thinking of cases like

obsessively-careful-lisp-system> (defun foo (l)
                                   (dolist (i l)
                                     (function-which-wants-a-fixnum i)))

Warning: I is not known to be a fixnum for FUNCTION-WHICH-WANTS-A-FIXNUM.

obsessively-careful-lisp-system> (defun foo (l)
                                   (dolist (i l)
                                     (declare (type (or fixnum null) i))
                                     (function-which-wants-a-fixnum i)))
Warning: Still not good enough, sorry.

obsessively-careful-lisp-system> (defun foo (l)
                                   (dolist (i l)
                                     (declare (type fixnum i))

Warning: NIL is not a fixnum. Moan, complain. Whine.

obsessively-careful-lisp-system> (defun foo (l)
                                   (dolist (i l)
                                     (locally (declare (type fixnum i))
                                      (function-which-wants-a-fixnum i))))

Warning: Type is now OK, but I am having to insert checks.  Grumble.

obsessively-careful-lisp-system> (exit)
$ rm -rf /local/packages/obsessively-careful-lisp-system
$ ftp less-obessive-lisp-systems-r-us.com

Really it would just be a nice thing to do to make an idiom which
people might want to use easy for them to use.  Quite apart from any
performance issues, I use declarations for documentation of code, and
I really don't want to have to insert completely spurious LOCALLYs or
LETs, or weaken, and also make less readable, declarations which the
system should easily be able to do itself in a suitable and completely
automatic way.  I want code I write to be readable and documented, and
not to spend its time pandering to some silly restriction in the
language or implementation.  If I enjoyed that I'd use C++.

So to throw the ball back at the implementors: is there anything wrong
with my scheme (rebind the variable around the return form,
reinserting declarations while either removing or suitably weakening
type declarations for the iteration variable?  How hard is this to
do?  Does it conform?

--tim
From: Joe Marshall
Subject: Re: dolist type declaration
Date: 
Message-ID: <znob2kz8.fsf@ccs.neu.edu>
Tim Bradshaw <···@cley.com> writes:

> obsessively-careful-lisp-system> (defun foo (l)
>                                    (dolist (i l)
>                                      (locally (declare (type fixnum i))
>                                       (function-which-wants-a-fixnum i))))
> 
> Warning: Type is now OK, but I am having to insert checks.  Grumble.

Why would it have to insert checks?  The local declaration is your
promise to the compiler that I is of type fixnum despite what it
thinks it knows.

> Really it would just be a nice thing to do to make an idiom which
> people might want to use easy for them to use.  

A macro, perhaps?
From: Tim Bradshaw
Subject: Re: dolist type declaration
Date: 
Message-ID: <ey3el5mxhhp.fsf@cley.com>
* Joe Marshall wrote:

> Why would it have to insert checks?  The local declaration is your
> promise to the compiler that I is of type fixnum despite what it
> thinks it knows.

Some systems don't take this attitude.

> A macro, perhaps?

yes.  One called DOLIST for instance.  Preferably one I don't have to
reimplement, but which the language provides: if I wanted to spend my
time implement basic features which are pleasant to use on top of ones
that aren't, I'd use scheme.

--tim
From: Nils Goesche
Subject: Re: dolist type declaration
Date: 
Message-ID: <ly3cm23qsr.fsf@cartan.de>
Tim Bradshaw <···@cley.com> writes:

> $ rm -rf /local/packages/obsessively-careful-lisp-system

...

> * Joe Marshall wrote:
> 
> > A macro, perhaps?
> 
> yes.  One called DOLIST for instance.  Preferably one I don't have to
> reimplement, but which the language provides: if I wanted to spend my
> time implement basic features which are pleasant to use on top of ones
> that aren't, I'd use scheme.

Thank you very much; I was beginning to question my sanity.

To the implementors among you: Yes, it might be undefined behavior
according to the standard but nevertheless, it is quite obvious that a
user who writes

(dolist (i list)
  (declare (fixnum i))
  ...)

or even

(dolist (i list t)
  (declare (fixnum i))
  ...)

doesn't give a flying fuck about what I is bound to during the
evaluation of the result form (if there is one at all).  If your
implementation makes a superflous binding/assignment there you should
rather spend your time thinking about how you can optimize it away
rather than how you can make your users really hate you.

I have said it numerous times already but apparently not often enough:
The standard is not a mathematical document.  Beware: If you get so
obsessive about it, some day somebody will point out an outright
contradiction in it and your heads are going to explode.  See
Cronenberg's ``Scanners�� for a graphic illustration of how
unfortunate an event that can be.  People around you will be offended
by your appearance and not invite you to parties and conferences
anymore.

As a litmus test, think about

(defconstant +foo+ '(bar baz))

Yes, if this form is evaluated again, your system will realize that
the new value isn't EQL to the old one and this is undefined behavior
according to the standard.  So generate a warning if you must
(preferably one I can switch off).  But if you even feel a glimpse of
an urge to generate an error there, even a continuable one, you should
immediately stop coding and watch ``Scanners�� again.

This is Lisp.  Trust me, I know what I'm doing. (Sledge Hammer)

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0
From: Marco Antoniotti
Subject: Re: dolist type declaration
Date: 
Message-ID: <ei49a.282$uq6.17987@typhoon.nyu.edu>
Tim Bradshaw wrote:

> Really it would just be a nice thing to do to make an idiom which
> people might want to use easy for them to use.  Quite apart from any
> performance issues, I use declarations for documentation of code, and
> I really don't want to have to insert completely spurious LOCALLYs or
> LETs, or weaken, and also make less readable, declarations which the
> system should easily be able to do itself in a suitable and completely
> automatic way.  I want code I write to be readable and documented, and
> not to spend its time pandering to some silly restriction in the
> language or implementation.  If I enjoyed that I'd use C++.
>
> So to throw the ball back at the implementors: is there anything wrong
> with my scheme (rebind the variable around the return form,
> reinserting declarations while either removing or suitably weakening
> type declarations for the iteration variable?  How hard is this to
> do?  Does it conform?


The issue here is not whether the implemetors agree.  The issue is that 
we, as a community, need a place where implemetors gather and issue 
common statemets of future compliance regarding such matters.

So the

(locally (declare (type (simple-list fixnum) fl))
   (dolist (i fl)
      (declare (type fixnum i)) ; Note that this should be redundant.
      ....))

Actually gets expanded with the two-blocks trick done by CMUCL.

Cheers

--
Marco Antoniotti
From: Tim Bradshaw
Subject: Re: dolist type declaration
Date: 
Message-ID: <ey3adgaxgs0.fsf@cley.com>
* Marco Antoniotti wrote:

> The issue here is not whether the implemetors agree.  The issue is
> that we, as a community, need a place where implemetors gather and
> issue common statemets of future compliance regarding such matters.

Well, maybe.  My issue is that I want to be able to write:

(dolist (i list-of-foos ...)
  (declare (type foo i))
  ...)

Because this communicates what I want to communicate, while either

(dolist (i list-of-foos)
  (locally (declare (type foo i))
   ...))

or 

(dolist (i list-of-foo)
  (declare (type (or null foo) i))
  ...)
   
are significantly harder to read, and I don't want a language which
makes me either obfuscate my code or reimplement a decent language on
top of it.

So I'd like to know: (1) does the standard allow this (I think it
does, but I may be wrong), and (2) how hard is it to implement (I
think it isn't very hard, since a rebinding-for-the-return-form
implementation can be done, and in order to be correct it only has to
pick up any special declarations and wrap them around the return
form)?

--tim
From: Wolfhard Buß
Subject: Re: dolist type declaration
Date: 
Message-ID: <m3u1eiyqfv.fsf@buss-14250.user.cis.dfn.de>
* Marco Antoniotti:
>
> The issue here is not whether the implemetors agree.  The issue is
> that we, as a community, need a place where implemetors gather and
> issue common statemets of future compliance regarding such matters.

* Tim Bradshaw:
>
> Well, maybe.  My issue is that I want to be able to write:
> 
> (dolist (i list-of-foos ...)
>   (declare (type foo i))
>   ...)
> 
> Because this communicates what I want to communicate, while either
> 
> (dolist (i list-of-foos)
>   (locally (declare (type foo i))
>    ...))
> 
> or 
> 
> (dolist (i list-of-foo)
>   (declare (type (or null foo) i))
>   ...)
>    
> are significantly harder to read, and I don't want a language which
> makes me either obfuscate my code or reimplement a decent language on
> top of it.
> 
> So I'd like to know: (1) does the standard allow this (I think it
> does, but I may be wrong), and (2) how hard is it to implement (I
> think it isn't very hard, since a rebinding-for-the-return-form
> implementation can be done, and in order to be correct it only has to
> pick up any special declarations and wrap them around the return
> form)?

1. Conforming Lispniks don't write
    (dolist (i list-of-foos ...) (declare (type foo i))...)!
   The Standard threatens with undefined consequences, and `An
   implementation is permitted to signal an error in this case.'

2. Instead of signaling an error all implementations could agree on
   one of the proposals. They could exclude any type declarations for
   the iteration variable (iv) in the final rebind of iv to nil.
   This could be nice, but still you are a nonconforming Lispnik if
   you write: (dolist (i list-of-foos ...) (declare (type foo i))...)

   There are solutions that doesn't make you a NCL:

   - Implementations could agree on a new declaration identifier
   elm-type mentioned in the initial post. Now conforming Lispniks
   could write
    (dolist (i list-of-foos ...) (declare (elm-type foo))...)
   But I dare no one would like it.

   - Edit the dolist specification.

-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)
From: Tim Bradshaw
Subject: Re: dolist type declaration
Date: 
Message-ID: <ey3vfyyvvf1.fsf@cley.com>
* Wolfhard Bu wrote:

> 1. Conforming Lispniks don't write
>     (dolist (i list-of-foos ...) (declare (type foo i))...)!
>    The Standard threatens with undefined consequences, and `An
>    implementation is permitted to signal an error in this case.'

Ok, well if that's the case then I would like this to be fixed in the
standard (or some future standard).

And what the hell is a `lispnik'.  I sure am not one, conforming or
otherwise.

--tim
From: Barry Margolin
Subject: Re: dolist type declaration
Date: 
Message-ID: <v_o9a.4$Nl5.923@paloalto-snr1.gtei.net>
In article <···············@cley.com>, Tim Bradshaw  <···@cley.com> wrote:
>* Wolfhard Bu wrote:
>
>> 1. Conforming Lispniks don't write
>>     (dolist (i list-of-foos ...) (declare (type foo i))...)!
>>    The Standard threatens with undefined consequences, and `An
>>    implementation is permitted to signal an error in this case.'
>
>Ok, well if that's the case then I would like this to be fixed in the
>standard (or some future standard).

I agree that this seems like a mistake in the standard.  It seems strange
for the declaration to apply during execution of the result-form, even
though the iteration variable will not hold any of the iteration values at
that time.

I'm not even sure why the iteration variable even needs to exist during the
result-form of a DOLIST.  I have a feeling that this came about as an
inappropriate parallel with DOTIMES.  In the case of DOTIMES, it's
understandable why the iteration variable will have the next value in the
sequence, and it may even be useful to reference it in the result-form.
But what's the point of having the iteration variable available at the end
of a DOLIST, when it will *always* contain NIL?

It might also be due to a traditional expansion of DOLIST into DO:

(do* ((.sublist. list-of-foos (cdr .sublist.))
      (i (car .sublist.) (car .sublist.)))
     ((null .sublist) . <result-forms>)
  <body>)

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Christophe Rhodes
Subject: Re: dolist type declaration
Date: 
Message-ID: <sqfzq2otx4.fsf@lambda.jcn.srcf.net>
Tim Bradshaw <···@cley.com> writes:

> obsessively-careful-lisp-system> (defun foo (l)
>                                    (dolist (i l)
>                                      (declare (type fixnum i))
> 
> Warning: NIL is not a fixnum. Moan, complain. Whine.
> 
> obsessively-careful-lisp-system> (defun foo (l)
>                                    (dolist (i l)
>                                      (locally (declare (type fixnum i))
>                                       (function-which-wants-a-fixnum i))))
> 
> Warning: Type is now OK, but I am having to insert checks.  Grumble.

Wait a minute?  In your first example, you would want not only your
obsessively-careful-lisp-system to not complain about the NIL at the
end of the iteration but also elide the checks that the second example
is forced to insert?  I don't understand -- surely if this
obsessively-careful-lisp-system is inserting checks it will insert
them in both cases?

> So to throw the ball back at the implementors: is there anything wrong
> with my scheme (rebind the variable around the return form,
> reinserting declarations while either removing or suitably weakening
> type declarations for the iteration variable?  How hard is this to
> do?  Does it conform?

I think it's clear that it is conforming to rewrite type declarations
-- after all, (a) even if their promise is always fulfilled a lisp
environment doesn't have to do anything with them and (b) if they're
not valid we're in undefined-behaviour-land anyway.  As for the
difficulty, well, that's a matter of parsing all things which could
possibly be type declarations [which is quite a lot; don't forget to
handle DEFTYPEs, which, according to one reading of the standard
allows you to do
  (deftype foo () 'fixnum)
  ...
  (... (declare (foo x)))
and so would need to be catered for] and rewriting them in the binding
clause for the return form.

However, I want first to understand what you think the difference
between the behaviours of your two examples is, apart from the fact
that one of them is conforming code and the other is not.  As far as I
can tell, there is no other difference in behaviour in e.g. CMUCL.

Cheers,

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Tim Bradshaw
Subject: Re: dolist type declaration
Date: 
Message-ID: <ey3r89lx5q4.fsf@cley.com>
* Christophe Rhodes wrote:

> Wait a minute?  In your first example, you would want not only your
> obsessively-careful-lisp-system to not complain about the NIL at the
> end of the iteration but also elide the checks that the second example
> is forced to insert?  I don't understand -- surely if this
> obsessively-careful-lisp-system is inserting checks it will insert
> them in both cases?

I was really just parodying a certain Lisp (I elided the nastiest bit:

obsessively-careful-lisp-system> (exit)

Error: EXIT requires an argument of type 
        (or (satisfies secret-internal-mad-package::valid-argument-to-exit)
            null)
really-annoying-and-obsessive-debugger> ^D

Warning: you should really exit the debugger with the command

   :exit-debugger-really :yes-i-really-mean-it :my-credit-card-number-is ...

   A small charge is made for exiting the debugger.

obsessively-careful-lisp-system> (exit 0)

Error: You don't get rid of me that easily

really-annoying-and-obsessive-debugger-this-time-with-an-absurdly-long-prompt> ^D

Warning: look, I told you what to say to exit the debugger.  Next time you use
   a shortcut I will delete all your files.  I know best, remember.

obsessively-careful-lisp-system> ^Z

[2]+  Stopped                 obsessive-cl

pkill -9 obsessive-cl

[2]+ Killed                   obessive-cl

OK, it wasn't very funny...)

> I think it's clear that it is conforming to rewrite type
> declarations [...]

I think so, too.  But In fact, it would be enough (I think) to simply
elide any non-SPECIAL declarations.  For added value, OPTIMIZE
declarations could be left in.  If there are other *mandatory*
declarations, then presumably the implementation knows what they are
(because they are all extensions, I think) and it can spot them and
leave them in.  I agree that spotting arbitrary type declaraions might
be hard...

> However, I want first to understand what you think the difference
> between the behaviours of your two examples is, apart from the fact
> that one of them is conforming code and the other is not.  As far as I
> can tell, there is no other difference in behaviour in e.g. CMUCL.

I don't think there is a difference in behaviour: at least, I hope
there isn't.  I think there is a difference in *clarity to the human
reader of the code*: the version without the strange LOCALLY / LET or
(or nil ...) type declaration is easier to read and communicates the
writer's intent more clearly.  And clarity of code to humans is
something that matters to me.

--tim
From: Joe Marshall
Subject: [OT] Re: dolist type declaration
Date: 
Message-ID: <el5l2462.fsf_-_@ccs.neu.edu>
Tim Bradshaw <···@cley.com> writes:

> I was really just parodying a certain Lisp (I elided the nastiest bit:
> 
> obsessively-careful-lisp-system> (exit)
> 
> Error: EXIT requires an argument of type 
>         (or (satisfies secret-internal-mad-package::valid-argument-to-exit)
>             null)
> really-annoying-and-obsessive-debugger> ^D
> 
> Warning: you should really exit the debugger with the command
> 
>    :exit-debugger-really :yes-i-really-mean-it :my-credit-card-number-is ...
> 
>    A small charge is made for exiting the debugger.
> 
> obsessively-careful-lisp-system> (exit 0)
> 
> Error: You don't get rid of me that easily
> 
> really-annoying-and-obsessive-debugger-this-time-with-an-absurdly-long-prompt> ^D
> 
> Warning: look, I told you what to say to exit the debugger.  Next time you use
>    a shortcut I will delete all your files.  I know best, remember.
> 
> obsessively-careful-lisp-system> ^Z
> 
> [2]+  Stopped                 obsessive-cl
> 
> pkill -9 obsessive-cl
> 
> [2]+ Killed                   obessive-cl
> 
> OK, it wasn't very funny...)

In something *completely* off-topic...

It used to be that exiting the Unix shell would log you out.  You
could type a control-D or simply `exit'.  Nowadays those things
generally print out a message:  Use `logout' to log out.

So I aliased someone's `logout' to echo  `Use ^D to log out.'
From: Tim Bradshaw
Subject: Re: [OT] Re: dolist type declaration
Date: 
Message-ID: <ey3smu1u4xk.fsf@cley.com>
* Joe Marshall wrote:

> It used to be that exiting the Unix shell would log you out.  You
> could type a control-D or simply `exit'.  Nowadays those things
> generally print out a message:  Use `logout' to log out.

Yes, that does seem to be a modern trend.  When I find systems set up
like that I usually use them to kill their administrators, which is
clearly the best thing for them (both the systems and the
administrators).  Though it's hard work to lift it, dropping an E10k
on some idiot's head is very satisfying.

--tim
From: Christophe Rhodes
Subject: Re: dolist type declaration
Date: 
Message-ID: <sq7kbdq123.fsf@lambda.jcn.srcf.net>
Tim Bradshaw <···@cley.com> writes:

> * Christophe Rhodes wrote:
> 
> > However, I want first to understand what you think the difference
> > between the behaviours of your two examples is, apart from the fact
> > that one of them is conforming code and the other is not.  As far as I
> > can tell, there is no other difference in behaviour in e.g. CMUCL.
> 
> I don't think there is a difference in behaviour: at least, I hope
> there isn't.  I think there is a difference in *clarity to the human
> reader of the code*: the version without the strange LOCALLY / LET or
> (or nil ...) type declaration is easier to read and communicates the
> writer's intent more clearly.  And clarity of code to humans is
> something that matters to me.

Right.  That's fair enough, and I certainly accept that as a valid
concern.  I was just confused by the apparent difference in behaviour.

Thanks,

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Wolfhard Buß
Subject: Re: dolist type declaration
Date: 
Message-ID: <m3ptp5zzty.fsf@buss-14250.user.cis.dfn.de>
* Christophe Rhodes:
> 
> As for the difficulty, well, that's a matter of parsing all things
> which could possibly be type declarations [which is quite a lot;
> don't forget to handle DEFTYPEs, which, according to one reading of
> the standard allows you to do
>
>   (deftype foo () 'fixnum)
>   ...
>   (... (declare (foo x)))
> and so would need to be catered for] and rewriting them in the binding
> clause for the return form.

It's not difficult. Just handle the non-standard declaration
specifiers like type specifiers. 

-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)
From: Christophe Rhodes
Subject: Re: dolist type declaration
Date: 
Message-ID: <sqvfz0qpsf.fsf@lambda.jcn.srcf.net>
rif <···@mit.edu> writes:

> > Are there many examples of lists of fixnums around, in live code?
> 
> I don't know about lists of fixnums, but I do dotimes and declare the
> loop variable to be a fixnum all the time.  I guess my code is
> non-conforming.  CMUCL seems to do what I expect.

No, for DOTIMES I think you're alright.

From the CLHS page for DOTIMES:

  Then result-form is evaluated. At the time result-form is processed,
  var is bound to the number of times the body was executed. 

So as long as you're not doing 
  (dotimes (i (1+ most-positive-fixnum))
    (declare (type fixnum i))
you should be alright.

Cheers,

Christophe 
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Wolfhard Buß
Subject: Re: dolist type declaration
Date: 
Message-ID: <m3n0kc7c3v.fsf@buss-14250.user.cis.dfn.de>
Unfortunately

 (dolist (i <list-of-type type-spec>...)
   (declare (type-spec i))...)

is in general *not* conforming CL, though implementations are free to
introduce new declaration identifiers such as elm-type e.g.

Now one can write

 (dolist (i <list-of-type type-spec>...)
   (declare (elm-type type-spec))...)

and our new dolist implementation expands this into something like

 (dolist (i <list-of-type type-spec>...)
   ...
   (let ((i i)
     (declare (type-spec i))...))...)

Costs:

 (dolist (<type-spec> list)
   (declare (elm-type <type-spec>))...)

The new implementation of dolist declares the elements of the list to
be of type <type-spec> not the iteration variable <type-spec> to be of
type elm-type. Free of charge!


 (dolist (<not-type-spec> list)
   (declare (elm-type <type-spec>))...)

does not declare the var <type-spec> to be of type elm-type. In this
rare? case programs will pay the price. 


Since implementations are free to define undefined behavior, they
could exclude the result form of dolist from the scope of a type
declaration for the iteration variable. (They will *not* exclude a
special declaration:) This might be the low cost possibility.


However, impatient fellow Lispnik will possibly not wait for a new
implementation of dolisp, and will use iterate instead:

 (iter (for elm in '(1/2 2/3 3/4))
       (declare (ratio elm))
       ...)


Btw, what's the history of dolist? 


-- 
"Hurry if you still want to see something. Everything is vanishing."
>                                        --  Paul C�zanne (1839-1906)

-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)
From: Tim Bradshaw
Subject: Re: dolist type declaration
Date: 
Message-ID: <ey31y1o4as9.fsf@cley.com>
* Wolfhard Bu wrote:
> Unfortunately
>  (dolist (i <list-of-type type-spec>...)
>    (declare (type-spec i))...)

> is in general *not* conforming CL, though implementations are free to
> introduce new declaration identifiers such as elm-type e.g.

Can you say why?  I can't see that this is implied by the spec.

--tim
From: Wolfhard Buß
Subject: Re: dolist type declaration
Date: 
Message-ID: <m3adgc727s.fsf@buss-14250.user.cis.dfn.de>
* Wolfhard Bu wrote:
>
> Unfortunately
>  (dolist (i <list-of-type type-spec>...)
>    (declare (type-spec i))...)
>
> is in general *not* conforming CL,


* Tim Bradshaw <···@cley.com> writes:
> 
> Can you say why?  I can't see that this is implied by the spec.

Please look at the answer
<···················@buss-14250.user.cis.dfn.de> I gave to rif.

-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)
From: Tim Bradshaw
Subject: Re: dolist type declaration
Date: 
Message-ID: <ey3u1ek2uk2.fsf@cley.com>
Ah, I understand this now.  You can get around this (and conform) by
wrapping a *new* binding of the iteration variable, to NIL, around the
result-form.

--tim
From: Wolfhard Buß
Subject: Re: dolist type declaration
Date: 
Message-ID: <m365r06w4z.fsf@buss-14250.user.cis.dfn.de>
Tim Bradshaw <···@cley.com> writes:
>
> Ah, I understand this now.  You can get around this (and conform) by
> wrapping a *new* binding of the iteration variable, to NIL, around the
> result-form.

My interpretation of [CLHS 6.2 DOLIST]... At the time result-form is
processed, var is bound to nil... is, that a result-form will be
processed, nil or user supplied. And at the time result-form is
processed, var is bound to nil.  That is, before result-form is
processed, always, independent of any user supplied result-form. And
this is the case of undefined behavior, etc...

Ok, that's my interpretation. 

-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)
From: Tim Bradshaw
Subject: Re: dolist type declaration
Date: 
Message-ID: <ey3znobh2fw.fsf@cley.com>
* Wolfhard Bu wrote:

> My interpretation of [CLHS 6.2 DOLIST]... At the time result-form is
> processed, var is bound to nil... is, that a result-form will be
> processed, nil or user supplied. And at the time result-form is
> processed, var is bound to nil.  That is, before result-form is
> processed, always, independent of any user supplied result-form. And
> this is the case of undefined behavior, etc...

Yes, that's correct.  Here is a sample expansion for DOLIST, with
gensyms replaced by real symbols to make it readable.  This is not
necessarily correct (in particular: I just typed it in), but it should
explain what I think can be done to avoid this issue:

(dolist (i '(1 2 3) i)
  (declare (type fixnum i))
  (print i))

-->

(let* ((tail '(1 2 3))
       (i (car tail)))
  (declare (type fixnum i))
  (tagbody
   top
   (progn
     (print i))
   (setf tail (cdr tail))
   (when tail
     (setf i (car tail))
     (go top)))
  (let ((i nil))
    i))

Note that you could discover whether this is happening or not by
capturing the binding of I in the body of the loop in a closure and
discovering that it wasn't, in fact, the same as the binding in effect
in the result form.  But that's OK, because it's explicitly left
unclear as to whether the iteraction variable is rebound or assigned.

I guess you could argue that the declaration is meant to apply to all
the bindings of the iteration variable, including whatever is in
effect in the result form.  Well ... maybe, but since that makes
declarations less useful and more cumbersome, I prefer my
interpretation. (I just checked, and it looks like CMUCL, at least
does more-or-less exactly this).

--tim
From: Wolfhard Buß
Subject: Re: dolist type declaration
Date: 
Message-ID: <m3isuz735s.fsf@buss-14250.user.cis.dfn.de>
* Wolfhard Bu wrote:
>
> My interpretation of [CLHS 6.2 DOLIST]... At the time result-form is
> processed, var is bound to nil... is, that a result-form will be
> processed, nil or user supplied. And at the time result-form is
> processed, var is bound to nil.  That is, before result-form is
> processed, always, independent of any user supplied result-form. And
> this is the case of undefined behavior, etc...

Additional Remark:
The iteration variable might be special, so the iteration variable
must explicitly be set or bound to nil which might collide with a type
declaration for the iteration variable.

[CLHS 3.3.4 Declaration Scope] ... Some iteration forms include
step, end-test, or result subforms that are also included in the scope
of declarations that appear in the iteration form. Specifically, the
iteration forms and subforms involved are:
... dolist, dotimes: result-form 

Tim Bradshaw <···@cley.com> writes:
> 
> Yes, that's correct.  Here is a sample expansion for DOLIST, with
> gensyms replaced by real symbols to make it readable.  This is not
> necessarily correct (in particular: I just typed it in), but it should
> explain what I think can be done to avoid this issue:
> 
> (dolist (i '(1 2 3) i)
>   (declare (type fixnum i))
>   (print i))
> 
> -->
> 
> (let* ((tail '(1 2 3))
>        (i (car tail)))
>   (declare (type fixnum i))
>   (tagbody
>    top
>    (progn
>      (print i))
>    (setf tail (cdr tail))
>    (when tail
>      (setf i (car tail))
>      (go top)))
>   (let ((i nil))
>     i))
> 
> Note that you could discover whether this is happening or not by
> capturing the binding of I in the body of the loop in a closure and
> discovering that it wasn't, in fact, the same as the binding in effect
> in the result form.  But that's OK, because it's explicitly left
> unclear as to whether the iteraction variable is rebound or assigned.

I think setqing or rebinding is not the point. It's an
implementational detail, though a reference implementation could be
helpful in specifying the semantics of declarations in macros.

> I guess you could argue that the declaration is meant to apply to all
> the bindings of the iteration variable, including whatever is in
> effect in the result form.

Exactly. That's the point.

> Well ... maybe, but since that makes
> declarations less useful and more cumbersome, I prefer my
> interpretation.

Agreed, type declarations for the dolist iteration variable are almost
superfluous, useless. In a previous post I mentioned a low cost
fix. Implemenations, i.e. all implementations could explicitly agree,
to define undefined behavior, i.e. require, that the iteration
variable is finally rebound to nil, and to exclude this binding from
the type declarations for the iteration variable. The dolist
specification could be edited...

Alternatively implemenatations could introduce a new specification
identifier. Please look at the initial post.

> (I just checked, and it looks like CMUCL, at least
> does more-or-less exactly this).

I think CMUCL did this to allow type declarations for the iteration
variable and to simultaneously suppress type error messages for
setqing or binding the iteration variable to nil.

The original CMUCL dolist implementation ignored special declarations
for the final binding of the iteration variable to nil. This is now
fixed in the cvs. The cvs version inserts all declarations, and I
think this is correct. But it is not useful, unfortunately.
Programmers should be encouraged to declare types, under certain
circumstances.


-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)