Why multiple namespaces?
Asked Answered
F

5

15

What is the rationale behind the design decision to have separate namespaces for values and functions in Common Lisp? What are the arguments for and against it?

Finance answered 25/7, 2010 at 8:13 Comment(0)
E
10

Common Lisp is basically a descendant from the original Lisp 1.5, or rather, a unification of its diverging dialects. The original Lisp 1.5 was what is nowadays called a Lisp-2. Because it was back in the sixties and the fact that you could pass functions to other functions was weird enough. No one would even think of letting them share the same namespace. Almost any language invented today with support for higher order functions and anonymous functions chooses the single-namespace approach. Including Clojure, which is otherwise closer to Common Lisp than to Scheme.

Scheme, like Clojure, wasn't originally a divergent dialect from Lisp 1.5, and for their purposes it makes sense.

Of course, in Clojure, vectors, hash maps, sets and all that can also be applied to arguments, so in a sense a vector in Clojure could be seen as a function that takes a natural number and produces a value from that.

Ealing answered 25/7, 2010 at 20:59 Comment(3)
(Probably also worth mentioning that a function in the very old lisp(s) was similar to a function in Emacs Lisp -- just a list that starts with lambda.)Resource
Really? I had no idea. So they just changed the bound variables low level in eval before applying it? Damn, that must have been expensive.Ealing
Rich Hicky talks about how he avoided some of the pitfalls normaly come with Lisp-1s. (look for clojure on blib.tv). I can't remember exactly so you want try to explain it myself.Blancablanch
E
16

Please see Richard P. Gabriel's paper Technical Issues of Separation in Function Cells and Value Cells for a full academic treatment of this subject.

Econometrics answered 25/7, 2010 at 8:18 Comment(0)
E
10

Common Lisp is basically a descendant from the original Lisp 1.5, or rather, a unification of its diverging dialects. The original Lisp 1.5 was what is nowadays called a Lisp-2. Because it was back in the sixties and the fact that you could pass functions to other functions was weird enough. No one would even think of letting them share the same namespace. Almost any language invented today with support for higher order functions and anonymous functions chooses the single-namespace approach. Including Clojure, which is otherwise closer to Common Lisp than to Scheme.

Scheme, like Clojure, wasn't originally a divergent dialect from Lisp 1.5, and for their purposes it makes sense.

Of course, in Clojure, vectors, hash maps, sets and all that can also be applied to arguments, so in a sense a vector in Clojure could be seen as a function that takes a natural number and produces a value from that.

Ealing answered 25/7, 2010 at 20:59 Comment(3)
(Probably also worth mentioning that a function in the very old lisp(s) was similar to a function in Emacs Lisp -- just a list that starts with lambda.)Resource
Really? I had no idea. So they just changed the bound variables low level in eval before applying it? Damn, that must have been expensive.Ealing
Rich Hicky talks about how he avoided some of the pitfalls normaly come with Lisp-1s. (look for clojure on blib.tv). I can't remember exactly so you want try to explain it myself.Blancablanch
C
8

Though there may be plenty of arguments each way in theory, I'd bet that it is largely philosophical in origin. Scheme, a Lisp-1, prefers elegance over practicality, and chose the same define syntax for variables and functions, which makes a single namespace feel natural (and encourages a functional style of programming). Common Lisp tends to prefer practicality and power over elegance, and was an attempt at consensus-building, so seeing an existing two-namespace solution broadly accepted and working well, accepted it.

In practice, however, it mostly means three things:

  • In Common Lisp (and other Lisp-2's), you have to use funcall a lot
  • In Scheme (and other Lisp-1's), you have to be careful not to override needed function names with variables; e.g. function arguments like lst instead of list
  • On the Internet, there will be arguments

It is one major factor in why some people prefer one Lisp to another, however.

Comstock answered 25/7, 2010 at 12:10 Comment(2)
The results of the difference goes deeper than just using funcall or avoiding name clashes: using higher order functions in Scheme is more natural, therefore more idiomatic, therefore compilers will work hard to optimize it. In CL, however, if you're using defvar to define a variable, and then funcall it, then compilers are very likely to compile it to much slower code than using a function definition. This is similar to CLers preferring loop constructs, and schemers preferring tail-calls instead. But of course your third point is the most important one...Resource
That's true, and a part of what I meant by "encourages a functional style of programming" --- thanks for making it more explicit.Comstock
V
4

I actually like having several namespaces (more than two even); it makes things easier for the user and the compiler-writer (implementation):

CL-USER> (defclass test () ())
#<STANDARD-CLASS TEST>
CL-USER> (defun test ())
TEST
CL-USER> (defparameter test 42)
TEST

CL-USER> (describe 'test)
COMMON-LISP-USER::TEST
  [symbol]

TEST names a special variable:
  Value: 42

TEST names a compiled function:
  Lambda-list: ()
  Derived type: (FUNCTION NIL (VALUES NULL &OPTIONAL))
  Source form:
    (LAMBDA ()
      (DECLARE (MUFFLE-CONDITIONS COMPILER-NOTE))
      (PROGN
       (SB-INT:NAMED-LAMBDA TEST
           NIL
         (BLOCK TEST))))

TEST names the standard-class #<STANDARD-CLASS TEST>:
  Direct superclasses: STANDARD-OBJECT
  No subclasses.
  Not yet finalized.
  No direct slots.

; No value

CL-USER> (make-instance 'test)
#<TEST {1005B1D601}>
CL-USER> (test)
NIL
CL-USER> test
42
CL-USER> 
Viscus answered 25/7, 2010 at 9:22 Comment(4)
Can you explain why you think "it makes things easier for the user"? I've not written much Scheme, but I have written a fair amount of Python, and never had a problem with wanting to give a class, instance, and/or method the same name. For that matter, even in Common Lisp where I can re-use names like this, I don't think I ever have. Instances tend to be nouns, functions tend to be verbs, etc.Linden
@Ken: I routinely write things like (defun foo (list) (list (bar list))) in CL, which doesn't work with the single namespace. Having to name my arguments things like lyst or lst in Scheme makes me slightly crazy.Warfore
Pillsy: That's true. Then again, calling arguments list would drive me slightly crazy, too, since it's so non-descriptive. I'd call it source or target or haystack or words that says what the purpose of the list is. If I called params by their type, 90% of my args would be list. :-)Linden
To be honest the "list-as-parameter" argument was what ended up convincing me Lisp-2 was unnecessary for completely non-logical reasons: this situation is completely unbelievable (and when people repeatedly use the same single unbelievable example, it makes the position feel weak).Quotidian
C
0

In addition to the other issues mentioned above, having a separate namespace for functions makes CL's unhygienic macros much less likely to bite the macro user. In CL, a name bound at the point of call that appears within the expansion of a macro will have the definition used at the calling point, not the definition used where the macro is defined. So in a Lisp-1 version of CL, if a macro expands to a call on the LIST function, and LIST were defined as a variable at the point where the macro was called, the macro would malfunction. (Note that gensyms don't solve this problem, unlike the inverse problem which they do solve.)

This doesn't happen in Scheme because by default Scheme macros are hygienic: all the names used in the expansion of a macro have the meanings they had where the macro is defined, not where it is used.

Candycecandystriped answered 28/8, 2014 at 22:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.