[comp.lang.lisp] Types in Common Lisp

ram+@cs.cmu.edu (Rob MacLachlan) (02/18/91)

Subject: Re: In defense of call/cc (and a plug for T)
Date: 16 Feb 91 10:21:04 GMT

>PS. My own personal gripes with CL are [1] the type system is far too loose
>[2] user-defined types aren't guaranteed to be distinct from previous
>types
[11] type assertions
>are unchecked & are effectively promises rather than hints (I'd like both,
> thanks).

I think that you are to some degree confusing current implementation
practice with what is necessarily so about Common Lisp.  It is true that
Common Lisp very rarely guarantees that errors will be detected (although in
the ANSI standard, this does happen.)  But implementations are encouraged to
detect errors wherever possible.  This would be an academic distinction
were it not for the fact that there is now an implementation of CL that
is strict about types, namely CMU CL.  I think that the CL type system is
great, what is a loss is the previous implementations of it.

By default, the Python compiler for CMU CL checks all type assertions.  Type
checking (and other error checking) can be suppressed by the compilation
policy specified in OPTIMIZE declarations.  This means that you can write
programs with declarations, getting the benefit of automatic checking of
type assertions.  In code that is performance critical, and that you are
confident of, you may turn off type checking (though due to level of type
check optimization, this may only get you 20%)

In addition to the basic type assertions given for efficiency reasons (such
as SIMPLE-STRING, FIXNUM), type assertions such as (OR NODE (MEMBER :END))
are also useful (and checked precisely.)  Python also gives compile-time
type warnings when its extensive type inference detects code that cannot
execute without an error.

> [3] equality doesn't work the way it does in other lisps & is 
>a nasty source of problems (e.g. portability) 

Meaning what?  People are definitely unstatisfied with EQUAL and EQUALP, but
fixing it right in this round seemed too difficult, so they punted.

>[4] there's no multi-threading

Yes, this definitely seems to be necessary in a viable lisp product.  Both
Lucid and Franz have it, and we are planning it for CMU CL.  This is all
within a preemptive lightweight-process model, like stack groups.  I think
that there is hope for standardization on this once people realize that you
can have lightweight processes without having to discover the solution to
expressing parallel algorithms.  Stack groups are used for multiple
concurrent interaction activities, not parallelism.

As to CALL/CC: it is elegant, and seems to be useful for some purposes, but
it doesn't address the same problems as stack groups.  You need preemptive
scheduling, and this means that you need synchronization primitives.  A
somewhat different ball of wax...

>[5] I don't like keyword parameters/optional parameter etc and dislike
>paying a cost for a feature I don't use

Well, I agree that optionals are mostly a loss, but you shouldn't be paying
any penalty other than compiler complexity.  I am convinced keyword args are
a big win for complex interfaces.  Positional arguments start to lose it
above 5 or 6 arguments.  And keywords allow you to build general functional
interfaces, as in the generic sequence functions.  When combined with good
inline expansion and constant-folding (as in Python), you get inline code
as tense as any you could get from LOOP, etc.  Python has no special magic
for the keyword-accepting list functions such as MEMBER, we just make the
inline expansions avaliable.

>[7] the lack of temporary (transparent) hash-tables 
>(c.f. Poplog CL, T) [8] the lack of destroy actions (c.f. Poplog CL)

Weak pointers and finialization are a win, and I expect you will see them in
more CL implementations.  CMU has weak pointers.

>[12] the lack of a updaters (see Pop11) for an update
>model that can support abstraction (SETF is a compile-time thing).

I think that SETF functions address this issue.  It would have been nice if
they had gone with them from the beginning.

>
>On the other hand, CL gets my thumbs up for {1} putting lexical binding
>on the map once and for all {2} its excellent number model {3} the

Yes to lexical binding and numbers.  And with CMU CL, I think that serious
number-crunching is starting to become a real possiblity in CL.

>size of its library (implementations all too often are sloppy in doing
>this, see Poplog CL for an implementation that avoids dragging in every bit
>of code (even the different cases of FORMAT are separately loaded)) which
>I suppose could be better thought out 

Part of the problem here is that most Unix'es are stuck with crude VM
technology. If you have a good VM system, having *everything* in one
huge mapped file really works pretty well.  Auto-loading is just slow
software demand-paging with no ability to page out.  It is possible that the
VM locality might be better, but with good system building tools, the
locality of a mapped system can be reasonable as well.  Running under Mach
has made us rather complacent about this, since a 24 meg program can start
up instantly.

>{4} for (mostly) successfully uniting 
>the Lisp community behind a single Lisp.

I also think this is quite important.  There is a positive role for
standardization in technological progress, even though most standards are
technically obsolescent by the time they are ready.  I think that CL will
have a longer life than many expect due to the great flexibility of Lisp.
It is now quite different from what it was, and it can become new things.
The next big catastrophe in progamming languages after object-orientation
will be parallelism.  We shall see...

  Robert A. MacLachlan (ram@cs.cmu.edu)

kers@hplb.hpl.hp.com (Chris Dollin) (02/19/91)

Steve Knight said:

   > [3] equality doesn't work the way it does in other lisps & is 
   >a nasty source of problems (e.g. portability) 

and got various responses on the lines "but how would the system know to do any
better?". Surely the answer is "it doesn't; but the programmer does, and they
can tell the system what to do"; viz, attatch to datatypes a user-definable
equality procedure with a suitable default (probably structural equality).

Thus a defstruct would have a equality-predicate option (eqp?) and all the
system types would come equipped with standard-defined eqp's (which might be
indirected through symbols, so they could be changed if one felt reckless). The
standard function eqp could then just dispatch through a type-indexed table.

The only question that comes to mind is whether the indexing should be on one
argument or two, and if on one, whether we assume that two objects of different
data-type can ever be equal - sorry eqp - eg is (eqp 1.0 1) true or not?


--

Regards, Kers.      | "You're better off  not dreaming of  the things to come;
Caravan:            | Dreams  are always ending  far too soon."

barmar@think.com (Barry Margolin) (02/20/91)

In article <KERS.91Feb19153205@cdollin.hpl.hp.com> kers@hplb.hpl.hp.com (Chris Dollin) writes:
>
>Steve Knight said:
>
>   > [3] equality doesn't work the way it does in other lisps & is 
>   >a nasty source of problems (e.g. portability) 
>
>and got various responses on the lines "but how would the system know to do any
>better?". Surely the answer is "it doesn't; but the programmer does, and they
>can tell the system what to do"; viz, attatch to datatypes a user-definable
>equality procedure with a suitable default (probably structural equality).
>
>Thus a defstruct would have a equality-predicate option (eqp?) and all the
>system types would come equipped with standard-defined eqp's (which might be
>indirected through symbols, so they could be changed if one felt reckless). The
>standard function eqp could then just dispatch through a type-indexed table.

I started writing a paper for Lisp Pointers on this subject a couple of
years ago, but never got it polished enough for submission.  I covered both
equality and copying.  My proposal used CLOS to define the generic
operations.

One issue I grappled with is that equality and copying are dependent on
context, not just types.  For instance, if you pass a pair of conses to an
equality predicate, the equality algorithm depends on whether you are
treating it as a tree, an association list, or a set.

My solution was to allow particular types to define keyword arguments so
that they can be further parametrized.  It's then up to the caller of the
function to realize that the data structure contains types that need such
parametrization, and supply the options if necessary.  For instance, the
method for CONSes accepts keywords that specify a predicate for determining
whether an object is a leaf node and how leaf nodes should be compared.

>The only question that comes to mind is whether the indexing should be on one
>argument or two, and if on one, whether we assume that two objects of different
>data-type can ever be equal - sorry eqp - eg is (eqp 1.0 1) true or not?

Since CLOS allows specialization on multiple arguments, I didn't constrain
this, although I think I specified that the default primary method treats
objects of different types as unequal.


>
>
>--
>
>Regards, Kers.      | "You're better off  not dreaming of  the things to come;
>Caravan:            | Dreams  are always ending  far too soon."


--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

jeff@aiai.ed.ac.uk (Jeff Dalton) (02/21/91)

In article <KERS.91Feb19153205@cdollin.hpl.hp.com> kers@hplb.hpl.hp.com (Chris Dollin) writes:
>
>Steve Knight said:
>
>   > [3] equality doesn't work the way it does in other lisps & is 
>   >a nasty source of problems (e.g. portability) 
>
>and got various responses on the lines "but how would the system know
>to do any better?". 

What I was, and still am, wondering is how it "doesn't work the way
it does in other Lisps" and why it's a "nasty source of problems
(eg, portability)".  Especially since EQL works reasonably for
numbers, unlike EQ in most Lisps.  (EQ doesn't work "reasonably"
for numbers in CL either, but CL has EQL while most other Lisps
did not.)

You've answered a different question, namely "How is equality handled
better in Pop than in Lisp?"  (I agree, by the way, that Pop handles
equality in a good way and that Common Lisp would be better if it
had an extendable equality predicate that could be specialized by
type.)

>Surely the answer is "it doesn't; but the programmer does, and they
>can tell the system what to do";

But the programmer _can_ tell the system what to do, by writing a
function and calling it, by writing a generic function and lots of
methods, etc.

> viz, attatch to datatypes a user-definable
>equality procedure with a suitable default (probably structural equality).

OK, here's something fairly close:

(defgeneric nice-equality (x y)
  (:method ((r string) (s string))
     (string= r s))                      ;case-sensitive
  (:method (x y)
     (equalp x y)))

This is, of course, another case where CL would probably have been
a better language if an object system had been included from the
start.

-- jd