From: Drew McDermott
Subject: Why is there no letstruct in Lisp?
Date: 
Message-ID: <3BDF121F.6141523D@yale.edu>
Why is there no letstruct in Lisp?  (letstruct would be to defstruct
as labels is to defun.)

So one might write

   (do ((i 0 (+ i 1)))
       ((= i 10))
     (letstruct ((foo (x i :type integer)
                      (y (- 10 i)
                         :type integer)))
        (let ((f (make-foo :x (* 10 i))))
           (format t "~d: ~s~%" i f))))

and get out

0 #S(FOO :X 0 :Y 10)
1 #S(FOO :X 10 :Y 9)
2 #S(FOO :X 20 :Y 8)
...
9 #S(FOO :X 90 :Y 1)

The scope of all names declared ('make-foo', 'foo-x', etc.) would be
local to the 'letstruct'.

One could also have letclass, analogous to defclass.  The only reason
I can think of for why these things don't exist is that structures and
classes are intrinsically global, because they are allocated on the
heap, and the garbage collector has to know about their details.
Still, it would be nice to have local bindings for the names.

                                             -- Drew McDermott

From: Barry Margolin
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <zAED7.30$hi1.205@burlma1-snr2>
In article <·················@yale.edu>,
Drew McDermott  <··············@yale.edu> wrote:
>Why is there no letstruct in Lisp?  (letstruct would be to defstruct
>as labels is to defun.)

Because the main purpose of structures is to allow you to pass a bunch of
things from one function to another as a single object.  If the structure
accessors only have local scope, how would the receiving function do
anything useful with the object?

>One could also have letclass, analogous to defclass.  The only reason
>I can think of for why these things don't exist is that structures and
>classes are intrinsically global, because they are allocated on the
>heap, and the garbage collector has to know about their details.

That's true of the data objects that are bound with LET bindings as well,
so obviously that's not the reason.

>Still, it would be nice to have local bindings for the names.


-- 
Barry Margolin, ······@genuity.net
Genuity, 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: Thomas F. Burdick
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <xcvady88x1h.fsf@hurricane.OCF.Berkeley.EDU>
Barry Margolin <······@genuity.net> writes:

> >One could also have letclass, analogous to defclass.  The only reason
> >I can think of for why these things don't exist is that structures and
> >classes are intrinsically global, because they are allocated on the
> >heap, and the garbage collector has to know about their details.
> 
> That's true of the data objects that are bound with LET bindings as well,
> so obviously that's not the reason.

Ah, but ordinary LET bindings don't create new types, just new
instances of types.  The type of the object has to be known everywhere
the object can be known, otherwise, well ... it doesn't even make
sense.  We certainly don't have type-less values, but that's what you'd
get if you did:

  (defun make-something ()
    (letstruct ((foo ...))
      (make-foo ...)))

  (let ((x (make-something)))
    (type-of x)) ;; what does type-of return???

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Barry Margolin
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <T1YD7.42$hi1.1325@burlma1-snr2>
In article <···············@hurricane.OCF.Berkeley.EDU>,
Thomas F. Burdick <···@hurricane.OCF.Berkeley.EDU> wrote:
>Barry Margolin <······@genuity.net> writes:
>
>> >One could also have letclass, analogous to defclass.  The only reason
>> >I can think of for why these things don't exist is that structures and
>> >classes are intrinsically global, because they are allocated on the
>> >heap, and the garbage collector has to know about their details.
>> 
>> That's true of the data objects that are bound with LET bindings as well,
>> so obviously that's not the reason.
>
>Ah, but ordinary LET bindings don't create new types, just new
>instances of types.

I was referring to the things that he said were "intrinsically global,
because they are allocated on the heap".  I thought that he was referring
to the instances, not the types.

-- 
Barry Margolin, ······@genuity.net
Genuity, 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: Thomas F. Burdick
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <xcvelnjzb71.fsf@apocalypse.OCF.Berkeley.EDU>
Barry Margolin <······@genuity.net> writes:

> In article <···············@hurricane.OCF.Berkeley.EDU>,
> Thomas F. Burdick <···@hurricane.OCF.Berkeley.EDU> wrote:
> >Barry Margolin <······@genuity.net> writes:
> >
> >> >One could also have letclass, analogous to defclass.  The only reason
> >> >I can think of for why these things don't exist is that structures and
> >> >classes are intrinsically global, because they are allocated on the
> >> >heap, and the garbage collector has to know about their details.
> >> 
> >> That's true of the data objects that are bound with LET bindings as well,
> >> so obviously that's not the reason.
> >
> >Ah, but ordinary LET bindings don't create new types, just new
> >instances of types.
> 
> I was referring to the things that he said were "intrinsically global,
> because they are allocated on the heap".  I thought that he was referring
> to the instances, not the types.

Actually, the original quote is quite ambiguous, isn't it?  I read it
as: structure and class types are intrinsically global, because
instances of them are allocated on the heap, which means the GC (or
anything else that can reach them), when it finds them, needs to know
about their type.  Maybe because that's my feelings on the issue :)

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Kaz Kylheku
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <SxFD7.133277$ob.3016449@news1.rdc1.bc.home.com>
In article <·················@yale.edu>, Drew McDermott wrote:
>Why is there no letstruct in Lisp?  (letstruct would be to defstruct
>as labels is to defun.)

let and labels are constructs for establishing value and function lexical
bindings for symbols, respectively.  There is no other kind of binding.

defstruct doesn't really bind; it causes a symbol to become a type,
but that's not a binding at all.

To make type defining work lexically, lexical environments would have
to carry extra baggage that associates symbols with types.  Moreover,
this mechanism would probably have to be dynamically scoped---see below.

>One could also have letclass, analogous to defclass.  The only reason
>I can think of for why these things don't exist is that structures and
>classes are intrinsically global, because they are allocated on the
>heap, and the garbage collector has to know about their details.
>Still, it would be nice to have local bindings for the names.

I don't think that's the reason at all; it's just insufficient utility.

It seems that programmers think of types as transcending textual
boundaries in the program. There isn't all that much use in having a
type that is not known outside of some narrow lexical scope,

Types tend to connect programs together at a wider level than that
of lexical scope; they establish that something created in one part
of the program will have its structure understood in another part.

What happens if you have some type in a lexical scope, and then
you return an object of that type? Since the type is not known
outside of that scope, what is the meaning of the value?

It would therefore seem that values associated with lexical types
implicitly need dynamic extent. But then what about passing them downward
in the dynamic environment into scopes where the type is not known either?
To fix that, the type information has to be dynamically scoped, not
lexically scoped, so that if you call some function and pass it an
object of local type, that type is dynamically known int he callee.

In some static languages, we can declare local types, such as local
classes in C++. The static system of declaration prevents instances of these
local types from escaping their scope, because all such communication
passes through declared interfaces, whose scope does not include the
definition of the local type. That is, the local type is not in scope of
the return type and parameter declarations. In general, an instance of
a type cannot exist in some part of a program where its type declaration
is not visible. (One counterexample is something like C++ polymorphism,
where an object can be used through a base class reference in regions
of the program where its actual type is not declared).

In Lisp, you can localize names using the package system.  It should
not be a grave problem that some type you would *like* to be local is
defined at the top level. The type is then globally known, but its name
has a home package, and can be a private symbol in that package.
And heck, you avoid the overhead of redefining the type each time
you enter the lexical scope where it is used.

As I recall, the only time I have ever defined a local type in one of the
Stone Age programming language was in order to create an enumeration for
the sake of labelling some states of a finite machine that is encapsulated
entirely within the block. I can't think of a C++ programming situation
that absolutely calls for a local class; you can always put the class
outside, and protect it with a namespace.
From: Barry Margolin
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <pCFD7.36$hi1.643@burlma1-snr2>
In article <·······················@news1.rdc1.bc.home.com>,
Kaz Kylheku <···@ashi.footprints.net> wrote:
>In article <·················@yale.edu>, Drew McDermott wrote:
>>Why is there no letstruct in Lisp?  (letstruct would be to defstruct
>>as labels is to defun.)
>
>let and labels are constructs for establishing value and function lexical
>bindings for symbols, respectively.  There is no other kind of binding.
>
>defstruct doesn't really bind; it causes a symbol to become a type,
>but that's not a binding at all.

But it defines a bunch of function names, and that's what he wants to make
lexical.  I.e. where defstruct expands into a bunch of DEFUNs, he expects
LETSTRUCT to expand into a bunch of FLETs.

-- 
Barry Margolin, ······@genuity.net
Genuity, 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: Gabe Garza
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <8zdsg3tn.fsf@kynopolis.org>
Drew McDermott <··············@yale.edu> writes:

> Why is there no letstruct in Lisp?  (letstruct would be to defstruct
> as labels is to defun.)

There've been a couple of times I thought something like this might be
useful--always when I had some data structure local to the definition
of some small number of functions (usually one) but I didn't want to
pollute the namespace with an obscure structure that would be used no
where else.  Often something I'd used a list to represent and then got
bitten by readability (CADDADR type stuff :))

Here's a crude stab at it: it just implements a structure as a vector
whose first element is the "type" name of the structure and whose
subsequent elements are the structure slots.  I don't define a type
predicate, and of course the "types" that it implements aren't at all
integrated with Lisp's type system (seeing as they're all vectors...)
Also, there's no support for initial elements or type specifiers.

(defun scat (&rest args)
  (intern 
   (apply #'concatenate (cons 'string  (mapcar #'string args))))))

(defmacro let-struct ((&rest struct-defs) &body body)
  `(flet
    (,@(loop for def in struct-defs
          collect
          (let ((slots (length def)))
            `(,(scat "MAKE-" (car def)) (&key ,@(cdr def))
              (let ((vector (make-array ,slots :initial-element nil)))
                (setf (aref vector 0) ',(car def))
                ,@(loop for slot in (cdr def)
                   and index from 1
                   collect `(setf (aref vector ,index) ,slot))
                vector)))
          append
          (loop for slot in (cdr def)
                and index from 1
           collect
             `(,(scat (car def) "-" slot) (struct)
               (aref struct ,index)))))
    ,@body))                          


(Poor) example: 

(let-struct ((point x y)
             (glue space stretch shrink))
  (let ((point (make-point :x 3 :y 5))
        (glue  (make-glue :space 3 :stretch 0 :shrink -1)))
    (print (sqrt (+ (expt (point-x point) 2)
                    (expt (point-y point) 2))))
    (values point glue)))

5.8309517 
#(POINT 3 5) ;
#(GLUE 3 0 -1)

   
From: Martin Cracauer
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <9rn78b$2se3$1@counter.bik-gmbh.de>
Drew McDermott <··············@yale.edu> writes:

>Why is there no letstruct in Lisp?  (letstruct would be to defstruct
>as labels is to defun.)

An even better question is why there is not

  (let-struct-instance  ((varname type))
     ...

with default struct contents and easily stack-allocatable with
non-pointer representation.

Implementations that don't want to bother with the stuff can just do
the normal struct thing.
-- 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Martin Cracauer <········@bik-gmbh.de> http://www.bik-gmbh.de/~cracauer/
FreeBSD - where you want to go. Today. http://www.freebsd.org/
From: Barry Margolin
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <YzFD7.35$hi1.451@burlma1-snr2>
In article <·············@counter.bik-gmbh.de>,
Martin Cracauer <········@counter.bik-gmbh.de> wrote:
>Drew McDermott <··············@yale.edu> writes:
>
>>Why is there no letstruct in Lisp?  (letstruct would be to defstruct
>>as labels is to defun.)
>
>An even better question is why there is not
>
>  (let-struct-instance  ((varname type))
>     ...
>
>with default struct contents and easily stack-allocatable with
>non-pointer representation.

What's the difference between that and:

(let ((varname (make-type)))
  (declare (dynamic-extent varname))
  ...)

If that's too much to type, create a macro.

-- 
Barry Margolin, ······@genuity.net
Genuity, 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: Kaz Kylheku
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <%FFD7.133280$ob.3016449@news1.rdc1.bc.home.com>
In article <·············@counter.bik-gmbh.de>, Martin Cracauer wrote:
>Drew McDermott <··············@yale.edu> writes:
>
>>Why is there no letstruct in Lisp?  (letstruct would be to defstruct
>>as labels is to defun.)
>
>An even better question is why there is not
>
>  (let-struct-instance  ((varname type))
>     ...
>
>with default struct contents and easily stack-allocatable with
>non-pointer representation.

Perhaps because you can write a macro to do it yourself, along the lines
of a transformer from:

    (let-struct-instance ((varname type)) ...body...)


into

    (let ((varname (make-instance 'type))) ...body...)

When you say stack-allocatable, do you mean that let-struct-instance
would implicitly declare the vars to have dynamic-extent?
From: Erik Naggum
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <3213491617118961@naggum.net>
* Drew McDermott <··············@yale.edu>
| Why is there no X in Lisp?

  Because those who request it have not specified and implemented X and
  given the community a good reason to adopt their design.  This is true
  for all values of X for which this annoyingly invalid question is asked.

///
-- 
  Norway is now run by a priest from the fundamentalist Christian People's
  Party, the fifth largest party representing one eighth of the electorate.
-- 
  Carrying a Swiss Army pocket knife in Oslo, Norway, is a criminal offense.
From: Tim Bradshaw
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <nkjy9lsrt0f.fsf@omega.tardis.ed.ac.uk>
Drew McDermott <··············@yale.edu> writes:

> Why is there no letstruct in Lisp?  (letstruct would be to defstruct
> as labels is to defun.)
> 
> So one might write
> 
>    (do ((i 0 (+ i 1)))
>        ((= i 10))
>      (letstruct ((foo (x i :type integer)
>                       (y (- 10 i)
>                          :type integer)))
>         (let ((f (make-foo :x (* 10 i))))
>            (format t "~d: ~s~%" i f))))
> 

What would (type-of (letstruct ((foo (x 1))) (make-foo))) say?

--tim
From: Drew McDermott
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <3BE02EDE.89A0DB42@yale.edu>
Tim Bradshaw wrote:

> Drew McDermott <··············@yale.edu> writes:
>
> > Why is there no letstruct in Lisp?  (letstruct would be to defstruct
> > as labels is to defun.)
> >
> > So one might write
> >
> >    (do ((i 0 (+ i 1)))
> >        ((= i 10))
> >      (letstruct ((foo (x i :type integer)
> >                       (y (- 10 i)
> >                          :type integer)))
> >         (let ((f (make-foo :x (* 10 i))))
> >            (format t "~d: ~s~%" i f))))
> >
>
> What would (type-of (letstruct ((foo (x 1))) (make-foo))) say?

Yes, I guess this is the real bug here.  Fixing it would require changing
the whole way Lisp handles type specifiers.  The fact that a type
specifier is a symbol practically requires that types have to be global.

Thanks to everyone for all the comments.  Several people argued that
'letstruct' would make it hard to share data among programs.  But of
course one could write
(letstruct ((foo ...))
   (defun fcn1-that-makes-foos ...)
   (defun fcn2-that-uses-foos ...))

or

(defun big-important-function (...)
   (letstruct ((important-but-local-type ...))
       (labels ((fcn1-that-makes-important-but-local-types
                    (...) ...)
                (fcn2-that-uses-them (...) ...))
          ...etc. etc. ...)))

I find myself wanting to do this all the time.  I'm surprised that others
don't.  (However, Erik, I'm not asking anyone to implement it; just idly
asking about it.)

Gabe Garza described how one could fake 'letstruct'.  Good idea.  Perhaps
I'll do that while I'm waiting for my super-duper statically-typed Lisp to
be finished :).

        -- Drew McDermott
From: Pierre R. Mai
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <87itcvijcy.fsf@orion.bln.pmsf.de>
Drew McDermott <··············@yale.edu> writes:

> > What would (type-of (letstruct ((foo (x 1))) (make-foo))) say?
> 
> Yes, I guess this is the real bug here.  Fixing it would require changing
> the whole way Lisp handles type specifiers.  The fact that a type
> specifier is a symbol practically requires that types have to be global.

I fail to see why type specifiers being symbols requires type to be
global.  E.g. string type specifiers don't seem to solve the problem
alluded to in the excerpt above.

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: Barry Margolin
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <ZM%D7.57$hi1.1779@burlma1-snr2>
In article <··············@orion.bln.pmsf.de>,
Pierre R. Mai <····@acm.org> wrote:
>Drew McDermott <··············@yale.edu> writes:
>
>> > What would (type-of (letstruct ((foo (x 1))) (make-foo))) say?
>> 
>> Yes, I guess this is the real bug here.  Fixing it would require changing
>> the whole way Lisp handles type specifiers.  The fact that a type
>> specifier is a symbol practically requires that types have to be global.
>
>I fail to see why type specifiers being symbols requires type to be
>global.  E.g. string type specifiers don't seem to solve the problem
>alluded to in the excerpt above.

I believe the point being made is that type-of should return a
namespace-independent representation of the type, like class-of does (it
returns the class metaobject, not the class name).  That way it would be
valid outside the lexical scope of the type name (if there were a
letstruct).

Notice that there's also no operation to undo a defstruct.  The best you
can do is fmakunbound all the functions that the defstruct defined, but the
type name still exists, and type-of will return it for any existing
instances of the structure.

-- 
Barry Margolin, ······@genuity.net
Genuity, 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: Paul Foley
Subject: Re: Why is there no letstruct in Lisp?
Date: 
Message-ID: <m2u1wglk6q.fsf@mycroft.actrix.gen.nz>
On Tue, 30 Oct 2001 15:48:31 -0500, Drew McDermott wrote:

> Why is there no letstruct in Lisp?  (letstruct would be to defstruct
> as labels is to defun.)

> So one might write

>    (do ((i 0 (+ i 1)))
>        ((= i 10))
>      (letstruct ((foo (x i :type integer)
>                       (y (- 10 i)
>                          :type integer)))
>         (let ((f (make-foo :x (* 10 i))))
>            (format t "~d: ~s~%" i f))))

> and get out

> 0 #S(FOO :X 0 :Y 10)

It bothers me that you think it should print #S(...), which ought to
be readable, but it won't be readable [except perhaps in the scope of
your LETSTRUCT, but only if it has dynamic, rather than lexical,
effect, which is not what you're asking for]

> The scope of all names declared ('make-foo', 'foo-x', etc.) would be
> local to the 'letstruct'.

So what would be the point?  You can't use it anywhere else (return
it, call other functions with it as an argument, etc).  Might as well
use separate variables for the slots of f, no?

-- 
The power of accurate observation is commonly called cynicism by those
who have not got it.
                                                    -- George Bernard Shaw
(setq reply-to
  (concatenate 'string "Paul Foley " "<mycroft" '(··@) "actrix.gen.nz>"))