Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!clyde.concordia.ca!nstn.ns.ca!news.cs.indiana.edu!sdd.hp.com!elroy.jpl.nasa.gov!forsight!gat From: gat@forsight.jpl.nasa.gov (Erann Gat) Newsgroups: comp.lang.lisp Subject: Re: In defense of call/cc (and a plug for T) Message-ID: <1991Feb14.223202.11475@elroy.jpl.nasa.gov> Date: 14 Feb 91 22:32:02 GMT References: <1991Feb12.233157.20820@elroy.jpl.nasa.gov> <1991Feb13.055938.22853@Think.COM> Sender: news@elroy.jpl.nasa.gov (Usenet) Organization: Jet Propulsion Laboratory, Pasadena, California Lines: 47 Nntp-Posting-Host: robotics.jpl.nasa.gov In article <1991Feb13.055938.22853@Think.COM> barmar@think.com (Barry Margolin) writes: >What if we were to add a coroutine facility, rather than a primitive for >building coroutines? See my previous posting, where I mentioned that we >prefer to define user-oriented facilities, rather than implementor-oriented >primitives. Common Lisp tries to be 1) powerful, 2) portable, 3) efficient. The trouble is that these three goals are often in conflict. Portability is usually served best by a small language with a few well-defined primitives that everything else is built on top of. Efficiency is usually served best by having a large number of less general constructs which can make lots of assumptions about the way they will be used. Power (e.g. lots of data types and built in procedures to compute with them) is often at odds with efficiency. (Canonical examples of languages which cater to portability, efficiency and power are Scheme, Fortran and Ada repectively.) CL has actually gone above and beyond the call for being all things to all people. However, its philosophy of catering to users rather than implementors leads to one extremely annoying side effect. If the thing you want to do just happens not to be one the ten zillion things that CL does, then you are just screwed. Examples of such things appear in this group regularly - things like coroutines or accessing the slot names of a structure. More often than not people just write implementation-dependent hacks to do what they want. ("Well," says Joe Programmer, "type-of returns the right thing on this machine, and so I'll go ahead and use it in this non-portable way and fix it up later.") What I do not understand is why you can't do both: first start with a set of primitives. Define the hell out of them so everyone agrees what they do. Then build all the user features on top of the primitives. It seems to me that this gives you the best of all possible worlds. Because the whole language is based on a small set of primitives, you can have complete implementations that consist of a small kernel and a huge (maybe PD) library of the user features (in source-code form). On the other hand, nothing prevents a manufacturer from implementing a compiler to optimize all the user features into tight code. Portability is enhanced because if some implementation has a bug, that feature can simply be redefined (albeit less efficiently) in terms of the primitives. Therefore, the answer to the original question is that I would rather have call/cc than coroutines. Tomorrow I might want to build engines (a really cool construct that somehow got lost in the shuffle). If I have call/cc I can do it myself. If I don't have call/cc then I have no recourse other than to go begging to LISP manufacturers or write my own compiler. (Ah! Maybe I have answered my own question there!) E.