From: Kent M Pitman
Subject: Re: Why MAKE-LOAD-FORM ?
Date: 
Message-ID: <sfw90wue7ck.fsf@world.std.com>
·······@netcom.com (Bill Newman) writes:

> Can anyone tell me why I need to mess around with MAKE-LOAD-FORM when
> I want to make struct-valued constants and cyclic data structures
> in Common Lisp? Why isn't the built-in
>
> #S(STRUCT-NAME :FIELD1 FIELD1-VALUE :FIELD2 FIELD2-VALUE ..)
>
> a good enough representation?

It's mostly a reasonable question to ask why there isn't a useful default,
but it is important to understand there is not a uniquely determined and
universally correct default.  What you ask for would be useful to some
people and not to some others.  By making you write it, you are reminded
of the fact that there may be other relationships that have to be saved
beyond identity.  Consider this prograrm:

(defvar *all-the-foos* '())

(defstruct (foo (:constructor make-foo-internal)) name a b)

(defun make-foo (&rest keys)
  (let ((the-foo (apply #'make-foo-internal keys)))
    (setf (gethash name *all-the-foos*) the-foo)
    foo))

Suppose that the user tries to compile this program and then save some 
foos into a file.  He gets no error, yet restoring foos don't set the
*all-the-foos* hash table because it's not MAKE-FOO-INTERNAL but MAKE-FOO
that does that, and the compiler can't know that this update is possible.

Another case involves slots that are demand-computed that don't need
to be saved and might waste enormous space to save.  Maybe they're
just caches but the cache is large and ephemeral.  By not confronting
you with the question of whether the object is best made by only
supplying values A and B but not recomputable cache value C, the
system contributes to bad programming style because the programmer is
misled into thinking the system is both taking care of him/her and
even worse is CAPABLE of taking care of him/her in the general case.

Now that doesn't mean I would be deadset opposed to what you suggest as
a system-wide default, and it might even be "more consistent" given that
#S syntax is already defined as you observe.  However, it's important to
understand that an equally reasonable question is "why is #S(...)
predefined, and shouldn't that definition be removed, requiring the
user to ask for it where it will be sufficient and appropriate?".
Why?  Because for both #S and MAKE-LOAD-FORM, having a predefined
default such as you want leads sometimes (even though not in the case
you apparently have) to:

 (a) wrong and outright broken in some applications, giving no 
     warning at all of such

 (b) highly inefficient in other applications, giving no warning
     at all of such

The key is in understanding that it's only an accident of your simple
situation that you could win with the default you request.

This issue is generally more subtle than it appears to many people and
is related to the issue of "intentional" vs "extensional" types.  Just
because you have a certain representation in play doesn't mean you can
infer from that representation all details about the intended use of
the representation.  It's true that often we do this in predefined
datatypes, but that's often because the use of those datatypes is more
well-defined by cultural convention and experience of use.  But
structs and classes are used for the things that are now well-defined;
it's one thing to make broad (and probably still false) claims like
"well, most of the time when I use lists, I want xxx to happen", but
it's even still harder to say "most of the time when I use data
structures I've not yet even conceived of, I'm sure it will be right
to do xxx".

For more on the subject of "intentional" vs "extensional" types, and
the traps involved in adding the "obvious" definitions of "seemingly
generic" functionality, see my Parenthetically Speaking (PS) column 
from Lisp Pointers on `EQUAL rights' at
 http://world.std.com/~pitman/PS/EQUAL.html