On Scheme

Thoughts on Scheme and teaching Scheme

Real Criticisms of Scheme

Posted by Peter on April 30, 2006

Recently I have noticed a tendency in the Common Lisp community to criticize Scheme, possibly to make the Scheme community look equally bad in its handling of such viewpoints. So to head off silly and/or baseless attacks on Scheme I have created a brief list of things that Scheme actually does have problems with. Maybe someone will even turn them into a SRFI eventually, when we reach some kind of a consensus as to what the best solutions are. Remember these are problems with the language, not an implementation. Even if a specific implementation has fixed them it doesn’t fix the language itself. The language needs to address such issues so that the implementations don’t become too fragmented.

Types
Types can be used to catch stupid programmer errors (the kind mere mortal make all the time, i.e. “which order do those parameters go in again?”) at compile time as well as to optimize away unnecessary run-time checks. Unfortunately the only types that Scheme supports are purely run-time. A type system also makes overloading functions based on the type of their parameters possible (efficiently, checking all parameter types on each call is not efficient), which can be extremely useful.

Macros
The macro system, although being nice for having hygienic safety and pattern matching, is at times cumbersome. It should be easy to create Common Lisp style macros when you want them. The macro system is also poorly documented (in my opinion).

Modules
The module system doesn’t support versioning well, nor does it support module “trees” (i.e. modules which have sub-modules declared within them). The fact that you can’t set! variables provided by modules feels arbitrary as well.

Objects
Scheme doesn’t have objects integrated into the language itself. Although I personally have argued that this can be considered a positive feature (see: here), I admit it can be annoying when to work on five different projects you have to learn five different object systems.

Errors
Trapping errors thrown at runtime, such as type errors, can be cumbersome and implementation dependant. Additionally there is no built-in syntax for providing the try-catch features available in other languages, although you can define your own with continuations.

Threads
Once again threads should be provided by the language, not by implementations.

Multiple Values
The values construct is cumbersome to work with. It requires special procedures to handle multiple values when it should be as simple as (f (p)) if f expects two parameters and p returns two values.

Lack of Compiler Hinting
This has partly been addressed under the problems with types, but as a whole Scheme lacks methods of hinting to the compiler what you are trying to do so it can optimize rationally. For example if defun was made part of the language we might allow the compiler to make the assumption that symbols created with defun could not be set!, and thus such functions could be inlined safely, ect.

Too Minimalist
Many of these problems resolve to the complaint that Scheme is too minimalist for its own good. Problems with types, threads, errors, objects, and modules are all symptoms of Scheme’s desire to be simple. Minimalism is good of course, because it makes the language easy to learn, implement, and optimize, but it has to be balanced with functionality, so that implementations don’t diverge to far when they are forced to implement features that the language doesn’t support.

Why use Scheme if has all these problems?

From this long list of faults you may think that I am encouraging you to drop Scheme. Many of these deficiencies have been resolved by individual implementations, which means that you can work as though they had been resolved, although there is a possibility that eventually you will have to update you code to bring it in line with the official solutions. Also Scheme still has some cool features that make it shine in comparison with Common Lisp, for example real continuations, guarantees of tail call optimization (no need for nasty do loops), and of course it is a Lisp-1. Additionally there is a formal process for revision, the SRFI, which allows the community to have their input, ensuring that Scheme improvements are really improvements, not fiat from some language deity. Even though these problems are currently open hopefully Scheme can later implement the best solutions to them, leaving the language as elegant as it is currently, unlike the solutions in Common Lisp, which often feel like hacks (just my opinion). If anyone does propose a SRFI to address one of these issues I would be grateful if they would let me know.

Advertisements

7 Responses to “Real Criticisms of Scheme”

  1. asdf said

    Most of these issues are resolved by SRFIs. Consider “final” SRFIs part of the language.

  2. Jeff Read said

    To answer many of these concerns, I think you should have a look at Shiro Kawai’s essay “The Schemer’s Way”; he lays out the case for drawing the distinction between language features and library features in a manner that leaves the language small and compact.

    http://www.shiro.dreamhost.com/scheme/docs/schemersway.html

    Concerning modules, I have to ask, what module system are you referring to? R5RS does not specify a standard module system for Scheme. Are you referring to PLT’s module system? Scheme48’s? The proposed R6RS module system? Whatever the case, it seems you have a problem with the inability to assign to module bindings; this strikes me as a feature, not a bug. set! is deprecated by many Schemers as it messes with variable semantics in various nasty ways; and the ability to mess with the bindings that modules expect to see only exacerbates the problem. I really have to know which module system you’re talking about to make a judgement call on that, though.

    Secondly, macros. The fact that Scheme is a Lisp-1 complicates macros considerably, and makes adoption of a defmacro-like system not the right thing (though some Schemes have implemented something along those lines). The problem becomes which bindings apply to the symbols in the expansion of a macro — the bindings at the site of macro definition, or at the site of macro invocation? R5RS syntax-rules macros ensure that define-time bindings cannot be obscured by invoke-time bindings. Sometimes you want finer control than is provided by this standard, and there are ways to achieve such control like syntactic closures and explicit renaming, that are more complicated than defmacro, but they make managing syntactic environments explicit which is a win. I recommend you do some reading in this regard; particularly Bawden and Rees’s paper on syntactic closures which lays out the issues nicely:

    ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-1049.pdf

    (Actually these lexical scope issues crop up in CL, too, but the separate value and function namespaces help minimize any clashes that take place.)

    With values and call-with-values, the design of Scheme favors clarity and explicitness over convenience.

    Your critique of errors is spot on; a generalized standard mechanism for trapping both errors raised by the system and user-defined exceptions would be an enormous win.

    You may want to read through the SRFIs, some of which address the issues we’ve been talking about.

  3. Jeff Read said

    s/cannot be obscured by/do not clash with/g in the message above.

  4. Relax, Jeff. “Schemer’s way” was a very rough article I hacked up to explain Scheme to non-Scheme people. I think the author of this entry already knew those things.

    Me, I kind of agree with this entry. I personally persuing some of those issues through my implementation, but I’m not in hurry. It seems that every other language is rushing to incorporate new shiny features, not knowing whether it is a good design or not in a long span. (It is very hard to know that before some number of practical applications are written.) So I guess it won’t harm that just one language taking the opposite—let implementation diverge for experimenting features and gain experience, then incorporate them into the language.

    By R10RS probably we’ll get what we want. With the current pace, it’ll be in less than 20 years!

  5. michaelw said

    Could you give some citations of “tendenc[ies] in the Common Lisp community to criticize Scheme, possibly to make the Scheme community look equally bad in its handling of such viewpoints”?

    Also, funnily, CL designers thought that continuations, TCO and Lisp-1-ness have their drawbacks which is why they went another route. Among them are some quite bright people (you might recognize Guy L. Steele), so dismissing their design decisions without trying to understand them seems bold.

    In short: full continuations were thought to be rarely needed (perhaps also a reason why the Scheme community still investigates in delimited continuations, shift/reset, etc.) and restrict some optimizations.

    TCO was (I think) shelved for political reasons (CL is a mix of other Lisps, some with commercial background), but there are do-loops, the loop macro, and the iterate library, each with its merits.

    Regarding Lisp-1 vs Lisp-2, somebody commented already that Lisp-1 makes things more complicated for doing away with FUNCALL. Gabriel and Pitman have written an essay about the Seperation of function and value cells. Some people even argue in favor of more namespaces (ISLISP has another one for special variables, for example).

    Also of interest: The Evolution of Lisp, A Critique of Common Lisp.

    Having two similar but different languages with different goals is fine with me. I do not feel the urge to make one or the other look bad. Language wars are boring, especially “within the family”.

  6. Bob said

    As a schemer, while I do agree with you (very strongly) on the lack of a standard module system being a problem, I do not agree that a standard object system would be a good thing, at all. I suppose I wouldn’t mind an object system if it were purely functional, as Oleg’s is, but then that would be just more like higher order functions than objects. As for the macros, I think define-syntax is more than powerful enough for my needs, but I suppose others might not feel the same way.

    For multiple values, I’m not sure if that really meshes well with non-static typing, (I’m not particularly opposed to static typing, but I don’t fully understand type inference so what can I say) I do agree that tuples would be nice, but isn’t that the same thing as lists? (I could be wrong here, just speculation). I would rather just cons the list and then map or filter later to get the individual values, but if I’m doing that, it’s likely that my function is too complicated anyway.

    I haven’t researched into type systems very extensively, but I think the domain language Kanren (scheme based) has Milner type inference. Since I’m quite ignorant on types at this point, I don’t know if that’s like the compile time type inference that Sml or Haskell has, but it is the same algorithm.

    As for exceptions, I could go either way on that one, but it isn’t that big of a deal for me, call/cc is there and that is enough for my needs.

    I appreciate your civil critique of Scheme, (unlike Erik Naggum) and although I don’t agree with most of it, I can see where you are coming from, and I do realize that those might be issues for CL’ers.

  7. […] This post was mentioned on Twitter by Tech news (BOT), m.y.ikegami_bot, News Feed MS, hndiary.com zerobot, HN Firehose and others. HN Firehose said: Real Criticisms of Scheme: http://bit.ly/gOsCTR […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: