From: Jim Cheng
Subject: Special use of let* ???
Date: 
Message-ID: <39A99DFA.5EDF3D78@yahoo.com>
 Recently , I just encountered the following codes:

 (let* (line  hash-table-for-x  array2  hash-table-for-y array1)
         ...........

 It is really strange to me since I thought that statement following
let* should be in (var value) pair, such as:
  (let*  (var1 value1)
          (var2 value2)
         ........

  So, is there any special use of let* ?

  Thanks!

Jim

From: Lyman Taylor
Subject: Re: Special use of let* ???
Date: 
Message-ID: <39A9A95E.7D2D2DCA@mindspring.com>
Jim Cheng wrote:
....
>  It is really strange to me since I thought that statement following
> let* should be in (var value) pair, such as:
>   (let*  (var1 value1)
>           (var2 value2)
>          ........

  Close,  it should look like 

    (let*  ( (var1 value1) 
             (var2 value2 ) ) 
      ..body .. ) 

  Else how would you distinguish between the let's body start 
  and the variables declaration's end? 

  What you observed is the short cut for intializing varaibles with 
  NIL.  The wisdom of initializing a variable that is to be bound
  to a hashtable to NIL might not be a good idea depending upon 
  what the rest of the code does. 
 
  The language legalese...
 http://www.xanalys.com/software_tools/reference/HyperSpec/Body/speope_letcm_letst.html

  Lyman
From: Coby Beck
Subject: Re: Special use of let* ???
Date: 
Message-ID: <mqiq5.37548$47.626884@news.bc.tac.net>
"Jim Cheng" <·······@yahoo.com> wrote in message
······················@yahoo.com...
> Recently , I just encountered the following codes:
>
>  (let* (line  hash-table-for-x  array2  hash-table-for-y array1)
>          ...........
>

This would be an unnecessary use of let*.

Both let and let* can be given just a variable name rather than a list of
name and value as elements in the let list.  The initial binding will then
be nil.

(let (a b (c 'foo))) is equivalent to (let ((a nil) (b nil) (c 'foo)))

Which brings to mind a related question:

I asked a junior programmer at work why he was using let* when he did not
use any of the new variables in subsequent bindings.  He replied that it is
faster than let in Allegro 5.x

I did one test and it seems to be true:

(let ((start (get-internal-real-time)))
  (dotimes (i 100000)
    (let ((a 1) (b 2))))
  (- (get-internal-real-time) start))
==>7200
(let ((start (get-internal-real-time)))
  (dotimes (i 100000)
    (let* ((a 1) (b 2))))
  (- (get-internal-real-time) start))
==>6420

Is this not a bit surprising?

Coby
From: Paul F. Dietz
Subject: Re: Special use of let* ???
Date: 
Message-ID: <39A9D73D.B5B357C2@interaccess.com>
Coby Beck wrote:
 
> I did one test and it seems to be true:
> 
> (let ((start (get-internal-real-time)))
>   (dotimes (i 100000)
>     (let ((a 1) (b 2))))
>   (- (get-internal-real-time) start))
> ==>7200
> (let ((start (get-internal-real-time)))
>   (dotimes (i 100000)
>     (let* ((a 1) (b 2))))
>   (- (get-internal-real-time) start))
> ==>6420
> 
> Is this not a bit surprising?


Speed of the interpreted forms is not very
interesting.

	Paul
From: Lyman Taylor
Subject: Re: Special use of let* ???
Date: 
Message-ID: <39AA02E8.81E9A6A6@mindspring.com>
"Paul F. Dietz" wrote:
> 
> Coby Beck wrote:
...
> > Is this not a bit surprising?

  Not when pausing to think that the "parallel binding" semantics
  probably incur some overhead to compute. 

> Speed of the interpreted forms is not very
> interesting.

  It is hard to tell since the compiler has some minimal smarts. :-)
  For instance, it is likely to remove both A and B from the 
  previous examples since they are dead in both versions.

  The following disassemble into essentially the same code. 

(defun let_test1  ( count )
 (let ( (sum 0) )
     (dotimes ( i count )
        (let  ( (a 1 ) (b 2 ))
          (setq sum (+ a (* b sum)))
        ))
    sum ))


(defun let_test2 ( count )
 (let ( (sum 0) )
     (dotimes ( i count )
        (let*  ( (a 1 ) (b 2 ))
          (setq sum (+ a (* b sum )))
        ))
  sum))



USER(52): (compile 'let_test1 )
LET_TEST1
NIL
NIL
USER(53): (compile 'let_test2 )
LET_TEST2
NIL
NIL
....
USER(60): (disassemble 'let_test1 )
;; disassembly of #<Function LET_TEST1>
;; formals: COUNT

;; code start: #x80e68e4:
   0: 9de3bf98     save %o6, #x-68, %o6
   4: 80a0e001     cmp  %g3, #x1
   8: 93d02010     tne  %g0, #x10
  12: 81100001     taddcctv     %g0, %g1, %g0
  16: a2100000     mov  %g0, %l1
  20: a0100000     mov  %g0, %l0
lb1:
  24: 90100010     mov  %l0, %o0
  28: 810a0018     tsubcc       %o0, %i0, %g0
  32: 0e800008     bvs  64
  36: 01000000     nop
  40: 2680000e     bl,a 96
 44: a4102004     mov  #x4, %l2
  48: 90100011     mov  %l1, %o0
lb2:
  52: 86102001     mov  #x1, %g3
  56: 81c7e008     jmp  %i7 + 8
  60: 91ea0000     restore      %o0, %g0, %o0
lb3:
  64: c4013e97     ld   [%g4 + -361], %g2       ; <_2OP
  68: 92100018     mov  %i0, %o1
  72: 9fc1200b     jmpl %g4 + 11, %o7
  76: 86182002     xor  %g0, #x2, %g3
  80: 80a10008     cmp  %g4, %o0
  84: 22bffff8     be,a 52
  88: 90100011     mov  %l1, %o0
  92: a4102004     mov  #x4, %l2
lb4:
  96: 90102008     mov  #x8, %o0
 100: c4013da7     ld   [%g4 + -601], %g2       ; *_2OP
 104: 92100011     mov  %l1, %o1
 108: 9fc1200b     jmpl %g4 + 11, %o7
 112: 86182002     xor  %g0, #x2, %g3
 116: a3048008     taddcc       %l2, %o0, %l1
 120: 2e800009     bvs,a        156
 124: 92100008     mov  %o0, %o1
lb5:
 128: 92102004     mov  #x4, %o1
 132: 99040009     taddcc       %l0, %o1, %o4
 136: 2e80000b     bvs,a        180
 140: c4013f87     ld   [%g4 + -121], %g2       ; +_2OP
lb6:
 144: a010000c     mov  %o4, %l0
 148: 10bfffe1     ba   24
 152: 81100001     taddcctv     %g0, %g1, %g0
lb7:
 156: c4013f87     ld   [%g4 + -121], %g2       ; +_2OP
 160: 90100012     mov  %l2, %o0
 164: 9fc1200b     jmpl %g4 + 11, %o7
 168: 86182002     xor  %g0, #x2, %g3
 172: 10bffff5     ba   128
 176: a2100008     mov  %o0, %l1
lb8:
 180: 90100010     mov  %l0, %o0
 184: 9fc1200b     jmpl %g4 + 11, %o7
 188: 86182002     xor  %g0, #x2, %g3
 192: 10bffff4     ba   144
 196: 98100008     mov  %o0, %o4
USER(61):
USER(61):
USER(61):
USER(61): (disassemble 'let_test2 )
;; disassembly of #<Function LET_TEST2>
;; formals: COUNT

;; code start: #x80e703c:
   0: 9de3bf98     save %o6, #x-68, %o6
   4: 80a0e001     cmp  %g3, #x1
   8: 93d02010     tne  %g0, #x10
  12: 81100001     taddcctv     %g0, %g1, %g0
  16: a2100000     mov  %g0, %l1
  20: a0100000     mov  %g0, %l0
lb1:
  24: 90100010     mov  %l0, %o0
  28: 810a0018     tsubcc       %o0, %i0, %g0
  32: 0e800008     bvs  64
  36: 01000000     nop
  40: 2680000e     bl,a 96
  44: a4102004     mov  #x4, %l2
  48: 90100011     mov  %l1, %o0
lb2:
  52: 86102001     mov  #x1, %g3
  56: 81c7e008     jmp  %i7 + 8
  60: 91ea0000     restore      %o0, %g0, %o0
lb3:
  64: c4013e97     ld   [%g4 + -361], %g2       ; <_2OP
  68: 92100018     mov  %i0, %o1
  72: 9fc1200b     jmpl %g4 + 11, %o7
  76: 86182002     xor  %g0, #x2, %g3
  80: 80a10008     cmp  %g4, %o0
  84: 22bffff8     be,a 52
  88: 90100011     mov  %l1, %o0
  92: a4102004     mov  #x4, %l2
lb4:
  96: 92100011     mov  %l1, %o1
 100: c4013da7     ld   [%g4 + -601], %g2       ; *_2OP
 104: 90102008     mov  #x8, %o0
 108: 9fc1200b     jmpl %g4 + 11, %o7
 112: 86182002     xor  %g0, #x2, %g3
 116: a3048008     taddcc       %l2, %o0, %l1
 120: 2e800009     bvs,a        156
 124: 92100008     mov  %o0, %o1
lb5:
 128: 92102004     mov  #x4, %o1
 132: 99040009     taddcc       %l0, %o1, %o4
 136: 2e80000b     bvs,a        180
 140: c4013f87     ld   [%g4 + -121], %g2       ; +_2OP
lb6:
 144: a010000c     mov  %o4, %l0
 148: 10bfffe1     ba   24
 152: 81100001     taddcctv     %g0, %g1, %g0
lb7:
 156: c4013f87     ld   [%g4 + -121], %g2       ; +_2OP
 160: 90100012     mov  %l2, %o0
 164: 9fc1200b     jmpl %g4 + 11, %o7
 168: 86182002     xor  %g0, #x2, %g3
 172: 10bffff5     ba   128
 176: a2100008     mov  %o0, %l1
lb8:
 180: 90100010     mov  %l0, %o0
 184: 9fc1200b     jmpl %g4 + 11, %o7
 188: 86182002     xor  %g0, #x2, %g3
 192: 10bffff4     ba   144
 196: 98100008     mov  %o0, %o4
USER(62):
From: Kent M Pitman
Subject: Re: Special use of let* ???
Date: 
Message-ID: <sfwd7itu77b.fsf@world.std.com>
In case no one has mentioned it, though
  (let ((x nil)) ...)
means the same as
  (let (x) ...)
the normal style convention I and others adhere to is that any use of
  (let (x) ...)
really implies a promise not to use X until it's been explicitly assigned,
and so the NIL that is done in the second case might as well be "uninitialized"
but for the fact that the GC wouldn't like that.
From: Roger Corman
Subject: Re: Special use of let* ???
Date: 
Message-ID: <39afe9f0.147930633@news>
On Sun, 27 Aug 2000 23:12:56 -0700, Lyman Taylor
<············@mindspring.com> wrote:

>"Paul F. Dietz" wrote:
>> 
>> Coby Beck wrote:
>...
>> > Is this not a bit surprising?
>
>  Not when pausing to think that the "parallel binding" semantics
>  probably incur some overhead to compute. 
>
> ...
>  The following disassemble into essentially the same code. 
>...

This is an interesting discussion to me. I have been preferring LET*
over LET in my own code, largely I think because I had this feeling
that it would perform better. I figured that LET would have to store
the new values temporarily before assigning the results. In fact I was
wrong. On the compiler I use, the execution of LET and LET* is
basically identical, with identical timings. I realize why now: the
compiler doesn't have to do any flow analysis, optimization or
anything like that. It simply assigns the variables as their values
are computed. The only difference is whether the variable names get
added to the name space of the compilation environment after all the
initialization code is run (in the case of LET) or one name at a time
(in the case of LET*). The thing is, this is done at compile time, and
has no effect whatsoever on the generated code (of course I mean if
there are no references to either of the names in the initialization
code). I should have realized this sooner, since I wrote the
compiler...   :-)

Roger Corman

·····@corman.net
From: Coby Beck
Subject: Re: Special use of let* ???
Date: 
Message-ID: <C9oq5.38180$47.632895@news.bc.tac.net>
"Paul F. Dietz" <·····@interaccess.com> wrote in message
······················@interaccess.com...
> Speed of the interpreted forms is not very
> interesting.

Good point.  So i did:

(defun test-let()
  (let ((start (get-internal-real-time)))
  (dotimes (i 50000000)
    (let ((a 1) (b 2))
    (+ a b)))
  (- (get-internal-real-time) start)))

(defun test-let*()
  (let ((start (get-internal-real-time)))
  (dotimes (i 50000000)
    (let* ((a 1) (b 2))
      (+ a b)))
  (- (get-internal-real-time) start)))

;;; Compiling file C:\Program Files\acl501\junk.lsp
;;; Writing fasl file C:\Program Files\acl501\junk.fasl
Warning: No IN-PACKAGE form seen in C:\Program Files\acl501\junk.lsp.
(Allegro Presto will be ineffective when loading a file having no IN-PACKAGE
form.)
;;; Fasl write complete
; Fast loading C:\Program Files\acl501\junk.fasl


> (test-let)
7630
> (test-let)
7580
> (test-let*)
6430
> (test-let*)
6420
> (test-let)
7630
> (test-let)
7690
> (test-let*)
6370
> (test-let*)
6430
>

Not likely to be the bottle neck in any application, but still seems
surprising....

Coby
From: Iban Hatchond
Subject: Re: Special use of let* ???
Date: 
Message-ID: <39AA5BDB.E3074355@emi.u-bordeaux.fr>
Coby Beck wrote:

> "Paul F. Dietz" <·····@interaccess.com> wrote in message
> ······················@interaccess.com...
> > Speed of the interpreted forms is not very
> > interesting.
>
> Good point.  So i did:
>
> (defun test-let()
>   (let ((start (get-internal-real-time)))
>   (dotimes (i 50000000)
>     (let ((a 1) (b 2))
>     (+ a b)))
>   (- (get-internal-real-time) start)))
>
> (defun test-let*()
>   (let ((start (get-internal-real-time)))
>   (dotimes (i 50000000)
>     (let* ((a 1) (b 2))
>       (+ a b)))
>   (- (get-internal-real-time) start)))
>
> ;;; Compiling file C:\Program Files\acl501\junk.lsp
> ;;; Writing fasl file C:\Program Files\acl501\junk.fasl
> Warning: No IN-PACKAGE form seen in C:\Program Files\acl501\junk.lsp.
> (Allegro Presto will be ineffective when loading a file having no IN-PACKAGE
> form.)
> ;;; Fasl write complete
> ; Fast loading C:\Program Files\acl501\junk.fasl
>
> > (test-let)
> 7630
> > (test-let)
> 7580
> > (test-let*)
> 6430
> > (test-let*)
> 6420
> > (test-let)
> 7630
> > (test-let)
> 7690
> > (test-let*)
> 6370
> > (test-let*)
> 6430
> >
>
> Not likely to be the bottle neck in any application, but still seems
> surprising....
>
> Coby

I did the same test with cmu cl
and i guess the result will surprise you or maybe you'll find this more
"logical" (in the sens of Espen Vestre post)

;; test-let.lisp

(defun test-let()
  (let ((start (get-internal-real-time)))
  (dotimes (i 50000000)
    (let ((a 1) (b 2))
    (+ a b)))
  (- (get-internal-real-time) start)))

(defun test-let*()
  (let ((start (get-internal-real-time)))
  (dotimes (i 50000000)
    (let* ((a 1) (b 2))
      (+ a b)))
  (- (get-internal-real-time) start)))


* (compile-file "home:test-let.lisp")

Python version 1.0, VM version Intel x86 on 28 AUG 00 02:27:20 pm.
Compiling: /amd/motodashi/krakatoa/home/hatchond/test-let.lisp 28 AUG 00
02:27:00 pm

Converted TEST-LET.
Compiling DEFUN TEST-LET:
Converted TEST-LET*.
Compiling DEFUN TEST-LET*:
Byte Compiling Top-Level Form:

home:test-let.x86f written.
Compilation finished in 0:00:01.

#p"/amd/motodashi/krakatoa/home/hatchond/test-let.x86f"
NIL
NIL

* (load "home:test-let.x86f")

; Loading #p"/amd/motodashi/krakatoa/home/hatchond/test-let.x86f".
T
* (test-let)

28
* (test-let*)

29
* (test-let)

28
* (test-let*)

28
* (test-let)

28
* (test-let*)

28
* (test-let)

28
*
From: Rainer Joswig
Subject: Re: Special use of let* ???
Date: 
Message-ID: <joswig-E687FA.02545528082000@news.is-europe.net>
In article <·····················@news.bc.tac.net>, "Coby Beck" 
<·····@mercury.bc.ca> wrote:

> faster than let in Allegro 5.x
> 
> I did one test and it seems to be true:
> 
> (let ((start (get-internal-real-time)))
>   (dotimes (i 100000)
>     (let ((a 1) (b 2))))
>   (- (get-internal-real-time) start))
> ==>7200
> (let ((start (get-internal-real-time)))
>   (dotimes (i 100000)
>     (let* ((a 1) (b 2))))
>   (- (get-internal-real-time) start))
> ==>6420
> 
> Is this not a bit surprising?

Btw., what is the value of INTERNAL-TIME-UNITS-PER-SECOND ?

-- 
Rainer Joswig, Hamburg, Germany
Email: ·············@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/
From: Espen Vestre
Subject: Re: Special use of let* ???
Date: 
Message-ID: <w63djpzyqp.fsf@wallace.nextel.no>
"Coby Beck" <·····@mercury.bc.ca> writes:
> I did one test and it seems to be true:
> 
> (let ((start (get-internal-real-time)))
>   (dotimes (i 100000)
>     (let ((a 1) (b 2))))
>   (- (get-internal-real-time) start))
> ==>7200
> (let ((start (get-internal-real-time)))
>   (dotimes (i 100000)
>     (let* ((a 1) (b 2))))
>   (- (get-internal-real-time) start))
> ==>6420
> 
> Is this not a bit surprising?

'get-internal-real-time' doesn't really tell you anything at all, your
computer might have been doing other things. get-internal-run-time
*might* be a bit better for such purposes (or use the time macro,
which gives you some more information).

As another poster pointed out, run times for intepreted forms are not
very interesting, and if you try to compile those loops, they'll
compile into noops and have nonmesurable runtime.

But if you look at the disassembly of two similar functions, you'll
see that simple uses of let and let* compiles into the same thing.

In order to stop the compiler from optimizing away everything, I've
placed a function call within the scope of the lets:

(defun lett ()
  (let ((a 1) (b 2))
    (foo a b)))

(defun lett* ()
  (let* ((a 1) (b 2))
    (foo a b)))


USER(142): (disassemble #'lett)
;; disassembly of #<Function LETT>
;; formals: 
;; constant vector:
0:	FOO

;; code start: #x48efbe4:
   0: 9de3bf98     save	%o6, #x-68, %o6
   4: 80a0e000     cmp	%g3, #x0
   8: 95d02010     tg	%g0, #x10
  12: 81100001     taddcctv	%g0, %g1, %g0
  16: 90102004     mov	#x4, %o0
  20: c4076022     ld	[%i5 + 34], %g2	; FOO
  24: 92102008     mov	#x8, %o1
  28: 9fc1200b     jmpl	%g4 + 11, %o7
  32: 86182002     xor	%g0, #x2, %g3
  36: 81c7e008     jmp	%i7 + 8
  40: 91ea0000     restore	%o0, %g0, %o0
USER(143): (disassemble #'lett*)
;; disassembly of #<Function LETT*>
;; formals: 
;; constant vector:
0:	FOO

;; code start: #x48efc6c:
   0: 9de3bf98     save	%o6, #x-68, %o6
   4: 80a0e000     cmp	%g3, #x0
   8: 95d02010     tg	%g0, #x10
  12: 81100001     taddcctv	%g0, %g1, %g0
  16: 90102004     mov	#x4, %o0
  20: c4076022     ld	[%i5 + 34], %g2	; FOO
  24: 92102008     mov	#x8, %o1
  28: 9fc1200b     jmpl	%g4 + 11, %o7
  32: 86182002     xor	%g0, #x2, %g3
  36: 81c7e008     jmp	%i7 + 8
  40: 91ea0000     restore	%o0, %g0, %o0
USER(144): 


-- 
  (espen)
From: Joachim Achtzehnter
Subject: Re: Special use of let* ???
Date: 
Message-ID: <m2zolsea7i.fsf@wizard.kraut.bc.ca>
Hi Coby,

You wrote:
> 
> I asked a junior programmer at work why he was using let* when he
> did not use any of the new variables in subsequent bindings.

If you had asked certain senior programmers they may have responded
with the question "Why not?". let and let* differ in meaning only when
one of the new variables is used in a subsequent binding. In the case
at issue there is no difference, hence either is valid. In a Lisp
style guide I once saw the recommendation that one should pick one of
the two as the default for such situations and stick to it. Which one
to use is then just a matter of preference.

Joachim

-- 
work:     ········@realtimeint.com (http://www.realtimeint.com)
private:  ·······@kraut.bc.ca      (http://www.kraut.bc.ca)
From: Kent M Pitman
Subject: Re: Special use of let* ???
Date: 
Message-ID: <sfwvgwg1h5p.fsf@world.std.com>
Joachim Achtzehnter <·······@kraut.bc.ca> writes:

> > I asked a junior programmer at work why he was using let* when he
> > did not use any of the new variables in subsequent bindings.
> 
> If you had asked certain senior programmers they may have responded
> with the question "Why not?". let and let* differ in meaning only when
> one of the new variables is used in a subsequent binding. In the case
> at issue there is no difference, hence either is valid. In a Lisp
> style guide I once saw the recommendation that one should pick one of
> the two as the default for such situations and stick to it. Which one
> to use is then just a matter of preference.

Indeed.  Dick Waters uses LET* by default and uses LET only to remind
himself that there is a funny relationship between the setups that
requires parallel binding.  He claims this is more natural, and
moreover probably more efficient because a dumb compiler is not
required (for lack of having done the flow analysis to tell) to buffer
up all the return values from each expression on the stack before
assigning the locals.

I suspect it's purely a matter of our having made LET have the shorter
name that we prefer to think of it as the better default.  Had the names
been swapped, or had LET* been called SET or something equally punchy,
I bet a lot more people would use it as the default.

The most important thing is, as Joachim here suggests, to subscribe to a
well-known default.  Of course, having a community-wide sense of what the
default is doesn't hurt--and I think that's why some people push for everyone
to make LET the default.  But as with most style rules, there just can't
be any absolutes.  Only priorities to weigh.  In the end, things like
programmer effectiveness have to weigh in, too.

It's more important to know why you do something a certain way than to
do it a certain right way, even a so-called "right" way, without knowing
the reason.  Dictated, thoughtless behavior is not wisdom, it's dogma.
From: Barry Margolin
Subject: Re: Special use of let* ???
Date: 
Message-ID: <rPOr5.52$j55.1977@burlma1-snr2>
In article <···············@world.std.com>,
Kent M Pitman  <······@world.std.com> wrote:
>I suspect it's purely a matter of our having made LET have the shorter
>name that we prefer to think of it as the better default.  Had the names
>been swapped, or had LET* been called SET or something equally punchy,
>I bet a lot more people would use it as the default.

To me it's not just the shortness, but the fact that "*" seems like a kind
of "special indicator", suggesting "Watch out, something unusual is
happening here!".  Like the way Scheme uses "!" for operators that modify
data in place.  So it seems natural to me that the version without the
special warning should be the default.  (I have the same philosophy in
other contexts -- if a car has a switch that changes a mode, such as the
Overdrive button, I assume that the manufacturer recommends the setting
that *doesn't* light up a dashboard indicator as the default).

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, 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: Dorai Sitaram
Subject: Re: Special use of let* ???
Date: 
Message-ID: <8oon7g$lqq$1@news.gte.com>
In article <·················@burlma1-snr2>,
Barry Margolin  <······@genuity.net> wrote:
>In article <···············@world.std.com>,
>Kent M Pitman  <······@world.std.com> wrote:
>>I suspect it's purely a matter of our having made LET have the shorter
>>name that we prefer to think of it as the better default.  Had the names
>>been swapped, or had LET* been called SET or something equally punchy,
>>I bet a lot more people would use it as the default.
>
>To me it's not just the shortness, but the fact that "*" seems like a kind
>of "special indicator", suggesting "Watch out, something unusual is
>happening here!".  Like the way Scheme uses "!" for operators that modify
>data in place.  So it seems natural to me that the version without the
>special warning should be the default.  (I have the same philosophy in
>other contexts -- if a car has a switch that changes a mode, such as the
>Overdrive button, I assume that the manufacturer recommends the setting
>that *doesn't* light up a dashboard indicator as the default).

"*" is simply a shorthand for plural (cf regexps),
rather than indicating any out-of-the-usual-ness.
let* is just many let's (where each of the let's
introduces only one variable).

--d
From: Barry Margolin
Subject: Re: Special use of let* ???
Date: 
Message-ID: <GPRr5.78$j55.2454@burlma1-snr2>
In article <············@news.gte.com>,
Dorai Sitaram <····@goldshoe.gte.com> wrote:
>In article <·················@burlma1-snr2>,
>Barry Margolin  <······@genuity.net> wrote:
>>In article <···············@world.std.com>,
>>Kent M Pitman  <······@world.std.com> wrote:
>>>I suspect it's purely a matter of our having made LET have the shorter
>>>name that we prefer to think of it as the better default.  Had the names
>>>been swapped, or had LET* been called SET or something equally punchy,
>>>I bet a lot more people would use it as the default.
>>
>>To me it's not just the shortness, but the fact that "*" seems like a kind
>>of "special indicator", suggesting "Watch out, something unusual is
>>happening here!".  Like the way Scheme uses "!" for operators that modify
>>data in place.  So it seems natural to me that the version without the
>>special warning should be the default.  (I have the same philosophy in
>>other contexts -- if a car has a switch that changes a mode, such as the
>>Overdrive button, I assume that the manufacturer recommends the setting
>>that *doesn't* light up a dashboard indicator as the default).
>
>"*" is simply a shorthand for plural (cf regexps),
>rather than indicating any out-of-the-usual-ness.
>let* is just many let's (where each of the let's
>introduces only one variable).

That may be the origin of the name, but it doesn't change the way it
appears.  For comparison, the *name* naming convention for special
variables was almost certainly chosen because the *'s make the names stand
out.

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, 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: Kent M Pitman
Subject: Re: Special use of let* ???
Date: 
Message-ID: <sfwk8cwf1a5.fsf@world.std.com>
Barry Margolin <······@genuity.net> writes:

> That may be the origin of the name, but it doesn't change the way it
> appears.  For comparison, the *name* naming convention for special
> variables was almost certainly chosen because the *'s make the names stand
> out.

Yeah, I think you're right that there is at least some degree of
reaction among people to the special character.  This same
morality-emphasizing device is employed in Scheme to make people feel
guilt about using "set!" (i.e., setq).
From: Tim Bradshaw
Subject: Re: Special use of let* ???
Date: 
Message-ID: <ey3n1hsrq91.fsf@tfeb.org>
* Dorai Sitaram wrote:

> "*" is simply a shorthand for plural (cf regexps),
> rather than indicating any out-of-the-usual-ness.
> let* is just many let's (where each of the let's
> introduces only one variable).

Hmmm.  And DO* is many DOs?
From: Dorai Sitaram
Subject: Re: Special use of let* ???
Date: 
Message-ID: <8ooqaa$lsd$1@news.gte.com>
In article <···············@tfeb.org>, Tim Bradshaw  <···@tfeb.org> wrote:
>* Dorai Sitaram wrote:
>
>> "*" is simply a shorthand for plural (cf regexps),
>> rather than indicating any out-of-the-usual-ness.
>> let* is just many let's (where each of the let's
>> introduces only one variable).
>
>Hmmm.  And DO* is many DOs?

No.  The "*" in DO* implies have the same
macroexpansion as for DO except substitute
the LETs by LET*s.  :-)

--d
From: Tim Bradshaw
Subject: Re: Special use of let* ???
Date: 
Message-ID: <ey3vgwbxne4.fsf@cley.com>
* Coby Beck wrote:

> OK.  How about if*?  : )

it kind of ought to be the same as COND -- a multiway if.  But
actually I think it's some weird Franz thing with then/else keywords?

--tim
From: Kent M Pitman
Subject: Re: Special use of let* ???
Date: 
Message-ID: <sfwitsgf15a.fsf@world.std.com>
Tim Bradshaw <···@tfeb.org> writes:

> * Dorai Sitaram wrote:
> 
> > "*" is simply a shorthand for plural (cf regexps),
> > rather than indicating any out-of-the-usual-ness.
> > let* is just many let's (where each of the let's
> > introduces only one variable).
> 
> Hmmm.  And DO* is many DOs?

DO* is such a puzzle.  I'd go farther than this.  I'd say that DO* is 
ill-named because the let : let* :: do : do* claim is pretty weak, depending
on the axis you cleave along.  Certainly it's not a simple nesting of DO's
in the way that LET* is a nesting of LETs.

You can make the case that DO* is a LET* around a loop with a lot of SETQ's
in it.  (Note that SETQ should be SETQ* and PSETQ should be SETQ.  Heh...
Isn't consistency wonderful?  Then DO* would be LET*+LOOP+SETQ* while DO
was LET+LOOP+SETQ.)
From: Barry Margolin
Subject: Re: Special use of let* ???
Date: 
Message-ID: <uoSr5.83$j55.2226@burlma1-snr2>
In article <···············@world.std.com>,
Kent M Pitman  <······@world.std.com> wrote:
>Tim Bradshaw <···@tfeb.org> writes:
>
>> * Dorai Sitaram wrote:
>> 
>> > "*" is simply a shorthand for plural (cf regexps),
>> > rather than indicating any out-of-the-usual-ness.
>> > let* is just many let's (where each of the let's
>> > introduces only one variable).
>> 
>> Hmmm.  And DO* is many DOs?
>
>DO* is such a puzzle.  I'd go farther than this.  I'd say that DO* is 
>ill-named because the let : let* :: do : do* claim is pretty weak, depending
>on the axis you cleave along.  Certainly it's not a simple nesting of DO's
>in the way that LET* is a nesting of LETs.

The original reason for the * in LET* may have been based on the Kleene
closure, but like many things in language the original reason is often
forgotten and the notation remains.  Once LET* became entrenched as an
entity by itself, it was natural to create the analogy: DO* is to DO as
LET* is to LET -- one binds sequentially, the other binds in parallel.

>You can make the case that DO* is a LET* around a loop with a lot of SETQ's
>in it.  (Note that SETQ should be SETQ* and PSETQ should be SETQ.  Heh...
>Isn't consistency wonderful?  Then DO* would be LET*+LOOP+SETQ* while DO
>was LET+LOOP+SETQ.)

Computer languages, like natural languages, are littered with
inconsistencies due to the vagaries of history.  When SETQ was named there
was no PSETQ, nor was there even a LET, let alone LET* (in those days,
anonymous lambdas or PROG were used if you wanted local variables).  There
may have been DO, but I doubt there was DO*.  So there was nothing to be
consistent or inconsistent with.

Maybe when the Common Lisp developers decided to extend SETQ to allow
multiple assignments they should have renamed it to PSETQ* -- the
sequential version of PSETQ. :)

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, 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: Patrick A. O'Donnell
Subject: Re: Special use of let* ???
Date: 
Message-ID: <rt3djjq5qr.fsf@ascent.com>
"Coby Beck" <·····@mercury.bc.ca> writes:
> I did one test and it seems to be true:
> 
> (let ((start (get-internal-real-time)))
>   (dotimes (i 100000)
>     (let ((a 1) (b 2))))
>   (- (get-internal-real-time) start))
> ==>7200
> (let ((start (get-internal-real-time)))
>   (dotimes (i 100000)
>     (let* ((a 1) (b 2))))
>   (- (get-internal-real-time) start))
> ==>6420
> 
> Is this not a bit surprising?

Not really.  You're timing the interpreter.

Practically speaking, I tend to think of let* as the more useful
default, since it's semantics are what I need in the vast majority of
cases.  However, my fingers were trained long, long ago to type the
seven characters of "(let ((" when I need locals, and they've proven
strongly resistant to retraining.

		- Pat