
JavaScript Isn't Scheme - munificent
http://journal.stuffwithstuff.com/2013/07/18/javascript-isnt-scheme/
======
Homunculiheaded
I learned JavaScript before "The Good Parts" was printed and more importantly
after I had been writing a lot of Common Lisp. I remember being really shocked
and excited when I realized how much JS had in common with lisp given that my
expectation when learning it was that I was in for an awful time.

I think the origins of the "JavaScript is Scheme!" meme have more to do with
the fact that you can pretty trivially re-implement all of the code from the
Little Schemer (including the applicative order y-combinator) in JavaScript,
than any of the reasons mentioned here. JavaScript still, imho, has nicer
closures and lambdas than most mainstream programming languages.

Actually, thinking back on it, I remember having a conversation with Prof.
Daniel Friedman about how similar the two language are and I believe his
response was something along the lines of: if you have the lambda calculus,
what else do you need?

Final nitpick: most of the "Y isn't really a lisp!" (another meme) articles
I've read always miss what I think is the biggest thing missing from all
languages compared to any lisp: symbolic expressions. To me this is the single
most underrated feature of lisp that almost no other programming languages
offer.

~~~
why-el
The points in the article are still not addressed in your comment. The
exercises in TLS can be programmed in pretty much any one of the mainstream,
dynamically-typed and lexically scoped languages (beginning with Ruby, which I
have partially done). The author is right; the hype around the phrase is
unjustified and js programmers should focus on the true merits of Javascript
alone.

~~~
voyou
That's true, but that any "dynamically-typed and lexically scoped languages"
with closures and first-class functions could be considered mainstream is
fairly new. Crockford wrote "JavaScript: The World's Most Misunderstood
Programming Language", which I think is the source of the idea that JavaScript
is like Scheme, back in 2001. At that point, Ruby was almost unknown, Python
was fairly minor, PHP didn't have closures or first-class functions; the other
major programming languages were statically-typed things like C++ and Java.

So I think it's worth remembering that it's really a very recent development
that we can now treat it as obvious that a language like JavaScript would
contain the things it has in common with Scheme.

~~~
stplsd
Perl was big in 2001 and had closures and first-class functions.

And let's not forget great book Higher-Order Perl: Transforming Programs with
Programs [http://hop.perl.plover.com/](http://hop.perl.plover.com/)

~~~
anonymous
Well, Perl is on a level not many languages dare touch. If I'm not mistaken,
you can execute arbitrary code during compilation and generate arbitrary
source. Which in turn might be executed to generate more stuff...

~~~
vinceguidry
You can do that with any language that has an eval function. Eval takes a
string and feeds it into the interpreter.

~~~
vinceguidry
For some reason I didn't see that he'd said, "during compilation". Perl is an
interpreted language, so there's no compilation stage. A compiled language is
modified in this way using a preprocessor. It doesn't really make sense to
claim it's possible to inject code during compilation, that's the entire
purpose of a compiler, to generate machine code from a syntax tree.

But code generation and execution during runtime, which is what I think you
meant, is capable in any language with eval().

~~~
chromatic
_Perl is an interpreted language, so there 's no compilation stage._

Perl claims to have a compilation stage, by which the documentation means that
the lexer and parser produce an optree, which the runtime phase traverses.
During that compilation stage, it's possible to run code which changes how the
parser will treat subsequent syntactic elements.

------
mnemonicsloth
Google "brendan eich javascript scheme". Result #1 is from Brendan Eich's
website:

 _I was recruited to Netscape with the promise of “doing Scheme” in the
browser..._

 _I’m happy that I chose Scheme-ish first-class functions and Self-ish (albeit
singular) prototypes as the main ingredients._

[https://brendaneich.com/2008/04/popularity/](https://brendaneich.com/2008/04/popularity/)

So "JS=Scheme" is not very crazy. Maybe it oversimplifies. But it's not
baseless. And it's short.

------
EzGraphs
The main reason the comparison between JavaScript and Scheme is helpful is
that it breaks the connection between JavaScript and Java. The first thing
many Java programmers do when trying to write JavaScript is to try to create a
class hierarchy (rather than using prototypical inheritance) using idioms from
Java. Although possible, it ends up awkward and confusing in most cases.
Understanding that functions are first-class and seeing functional idioms fall
out from there is a big paradigm shift for Java devs.

Obviously JavaScript isn't Scheme using the author's "top 10 defining
characteristics of Scheme." Crockford's analysis is on track - and John Resig
and Bear Bibeault highlight the same idea by introducing functions are really
fundamental to the languages more than objects (in "Secrets of a JavaScript
Ninja").

The language's history does imply the comparison as well. Eich's original
mandate was to "write Scheme for the browser" but he was later directed to
give his language a C-like syntax and to ride on the coat-tails of the hype
surrounding Java.

"JavaScript isn't Scheme" might not be accurate for folks schooled in the
finer points of Scheme. It is very useful to those who cut their teeth
learning Java.

~~~
dmpk2k
We might just as well claim that Javascript is Perl then. Javascript has a lot
more in common with Perl than it does Scheme; those things that both
Javascript and Scheme have in common are also common in many other languages.

Anyone trying to draw parallels between Javascript and Scheme isn't crossing
some pedantic line, they're off in crazyland. Or, more likely, they don't
understand both languages as well as they're implying.

------
fsck--off
> Scheme is even more Lisp than Lisp

That's not true. In fact, there are some prominent people in the Lisp
community who do not think that Scheme is a Lisp.

See this thread from 2002 on comp.lang.lisp (especially Pitman and Naggum's
comments) for more. If you are too young to have posted on C.L.L when Usenet
was still popular, and want to see what a full fledged flame war looks like,
look at the end of the thread.

Some people who posted there (including the OP) are on HN.

[https://groups.google.com/forum/#!topic/comp.lang.lisp/Bj8Hx...](https://groups.google.com/forum/#!topic/comp.lang.lisp/Bj8Hx6mZEYI\[1-25-false\])

~~~
kragen
There are people — like Pitman and Naggum — who argue for defining "Lisp" to
mean "Common Lisp" for political rather than technical reasons, essentially
because they want to stop the evolution of Lisp. (Those who haven't read the
thread might think I'm exaggerating.) Fortunately, they are relatively
irrelevant today, and Lisps like Clojure, Hy, and Racket are carrying on the
further development of Lisp.

~~~
lispm
But languages like Clojure, Hy or Racket are not a Lisp. They are Lisp-
derived/inspired/... languages. That's also why they don't have Lisp in their
name.

OTOH Lisps like Emacs Lisp, Common Lisp, ISLisp, and some others are still
carrying the core of the first Lisp. Basically you can run Lisp 1.5 code in
those without many changes.

Just like Java is not the new C. OTOH languages like C++ and Objective C still
support much of C. You can port C to C++ easily.

Over the history many other languages have been trying to replace Lisp: ML
(functional programming), Dylan (object-oriented programming), Logo, Scheme,
... all tried to modernize/improve Lisp. Now it is Clojure and some other
languages.

Still there are core Lisp languages which carry on the genes.

But not Clojure:

    
    
        Clojure 1.5.0-RC2
        user=> (car '(1 2))
        CompilerException java.lang.RuntimeException: Unable to resolve symbol: car in \
        this context, compiling:(NO_SOURCE_PATH:3:1)
    

What?

    
    
        user=> (append '(1 2) '(3 4))
        CompilerException java.lang.RuntimeException: Unable to resolve symbol: append \
        in this context, compiling:(NO_SOURCE_PATH:4:1)
    
    

What?

    
    
        user=> (assoc 'foo '((foo . 3)))
        ArityException Wrong number of args (2) passed to: core$assoc  clojure.lang.AFn\
        .throwArity (AFn.java:437)
    
        user=> (atom 'foo)
        #<Atom@2285af04: foo>
    

???

Does not look like it supports Lisp processing as defined by McCarthy:

[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.91....](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.91.4527&rep=rep1&type=pdf)

Additionally the Java error messages are especially irritating. I enter
Clojure code and get Java error messages.

Compare that with a real Lisp:

    
    
        bash-3.2$ java -jar abcl.jar
        Armed Bear Common Lisp 1.1.1
        Java 1.7.0_25 Oracle Corporation
        Java HotSpot(TM) 64-Bit Server VM
        Low-level initialization completed in 0.628 seconds.
        Startup completed in 1.968 seconds.
        Type ":help" for a list of available commands.
        CL-USER(1): (car '(1 2))
        1
        CL-USER(2): (append '(1 2) '(3 4))
        (1 2 3 4)
        CL-USER(3): (assoc 'foo '((foo . 3)))
        (FOO . 3)
        CL-USER(4): (bar 10)
        #<THREAD "interpreter" {6EEE1E2}>: Debugger invoked on condition of type UNDEFINED-FUNCTI\
        ON
          The function BAR is undefined.
        Restarts:
          0: CONTINUE     Try again.
          1: USE-VALUE    Specify a function to call instead.
          2: RETURN-VALUE Return one or more values from the call to BAR.
          3: TOP-LEVEL    Return to top level.
        [1] CL-USER(5): 
    

We even get Lisp error messages. The compiler is written in Lisp.
[http://svn.common-
lisp.net/armedbear/trunk/abcl/src/org/arme...](http://svn.common-
lisp.net/armedbear/trunk/abcl/src/org/armedbear/lisp/compiler-pass1.lisp)

Clojure may be a cool language, but the core of Lisp has been replaced in
parts with something else. List processing is different. It's now based on
'persistent' lazy sequences...

~~~
kragen
Rainer, are you seriously complaining that Clojure is not a Lisp because it
spells "car" as "first", "cdr" as "rest", and "append" as "concat"? That makes
as much sense as complaining that Interlisp is not a Lisp because it doesn't
have FEXPR.

In Clojure, your examples are spelled:

    
    
        (first '(1 2))
        (concat '(1 2) '(3 4))
        (get {:foo 3} :foo)       ; or (get {'foo 3} 'foo)
        (symbol? 'foo)            ; or (not (coll? 'foo))
    

And lots of things in the world irritate me for reasons that have nothing to
do with whether they are Lisp or not.

I'd like to point out that your examples wouldn't have worked in Lisp 1.5
either. You would have had to type, for example,

    
    
        CAR (QUOTE (1 2))
    

interactively.

~~~
lispm
Clojure does not implement Lisp lists. Just plain and simple. It may partly
look like Lisp lists. But they aren't. Functions are randomly either looking
compatible or not at all. ATOM does something completely different. CAR does
not exist. FIRST exists, but works on persistent lazy sequences (wonderful,
but it is not using Lisp-style chained cons cells).

Btw., LispWorks, plain:

    
    
        CL-USER 23 > CAR (QUOTE (1 2))
        1
    

A more complex example:

[http://www.informatimago.com/develop/lisp/com/informatimago/...](http://www.informatimago.com/develop/lisp/com/informatimago/small-
cl-pgms/wang.html)

~~~
kragen
You're mostly mistaken, and you've mostly been fooled by changing names.

Clojure lists aren't lazy, and they support the Lisp operations, under
slightly different names, and with the same asymptotic performance
characteristics you're used to, because they're made of chained cons cells.
The cons operation is implemented at
[https://github.com/clojure/clojure/blob/master/src/jvm/cloju...](https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentList.java#L60).
Your "more complex example" is a 1960 program written, originally, in
M-expressions; here's the first definition on the cited p.32:

    
    
        th1r[v;a1;a2;c1;c2] = [atom[v] → member[v;a1]∨
            th[a1;a2;cons[v;c1];c2];T → member[v;a2]∨
            th[a1;a2;c1;cons[v;c2]]]
    

As far as I know, there hasn't ever been a Lisp system that could parse and
run that, and certainly not LispWorks. But you can straightforwardly
transliterate it either into Lisp 1.5, or Common Lisp (although the post you
link doesn't bother; instead they wrote an interpreter for the incompatible
Lisp 1.5 syntax in Common Lisp), or into Clojure:

    
    
        (defn th1r [v a1 a2 c1 c2]
            (cond (symbol? v) (or (some #{v} a1) (th a1 a2 (cons v c1) c2))
                  true        (or (some #{v} a2} (th a1 a2 c1 (cons v c2)))))
    

The only weird thing here is using the set-membership test instead of MEMBER.

Compare the above to the LISP 1.5 version:

    
    
        (TH1R (LAMBDA (V A1 A2 C1 C2) (COND
            ((ATOM V) (OR (MEMBER V A1)
            (TH A1 A2 (CONS V C1) C2) ))
            (T (OR (MEMBER V A2) (TH A1 A2 C1 (CONS V C2))))
            )))
    

Clearly Lisp changed a lot between LISP 1.5 in 1962 and CLtL in 1984, not to
mention current Common Lisp practice; what you'd write in any modern Lisp
looks a lot more like the Clojure version than the LISP 1.5 version.

The set thing, though, points to a real difference in Clojure: it has a set
data type, and you're expected to use it instead of the list data type when
what you want is a set. It's still immutable, though, and supports efficient
nondestructive update, so if you decide to rewrite this as

    
    
        (defn th1r [v a1 a2 c1 c2]
            (if (symbol? v)
                (or (a1 v) (th a1 a2 (conj c1 v) c2))
                (or (a2 v) (th a1 a2 c1 (conj c2 v)))))
    

you can be assured that you're not totally hosing your program's performance.
It might get better, in fact, if the sets are large.

You could argue that adding sets (and finite maps) to Lisp is violating the
underlying essence of Lisp, in which you use conses for everything, but in
fact we already have vectors, hash tables, classes, structs, and closures in
all of the other Lisps you're citing, none of which were present in the Ur-
Lisp in 1960.

ATOM doesn't exist in Clojure, although you can define it. atom does, and yes,
it does something totally different from what ATOM did historically.

By "persistent" Clojure means "immutable". That is, there's no RPLACA or
RPLACD. But RPLACA and RPLACD weren't present in McCarthy's original proposal,
and they're hardly central to Lispiness. You could even argue that their
absence is Lispier, since it encourages functional programming and enables the
compiler to optimize it better, and indeed Racket already abandoned them a few
years back for that reason.

BTW, I was wrong about what you would have had to type at LISP 1.5's read-
apply-print-loop. You would have had to type

    
    
        CAR ((QUOTE (1 2)))
    

for obvious reasons.

~~~
lispm
I'm not mistaken. Look closer.

Of course Clojure sequences are lazy.

    
    
        (defn map
          ([f coll]
           (lazy-seq
            (when-let [s (seq coll)]
              (cons (f (first s)) (map f (rest s))))))
    

Inside a LAZY-SEQ the operations are just that.

They are also not acting like cons cells:

    
    
        user=> (cons 1 2)
        IllegalArgumentException Don't know how to create ISeq from: java.lang.Long   clojure.lang.RT.seqFrom (RT.java:496)
    

> As far as I know, there hasn't ever been a Lisp system that could parse and
> run that

What you saw in the file was the source code used by the first Lisp
implementation.

> an interpreter

That was no 'interpreter'. Mostly a different reader.

> what you'd write in any modern Lisp looks a lot more like the Clojure
> version than the LISP 1.5 version.

Not necessarily. See the Lisp source for
[http://www.shenlanguage.org/Download/download.html](http://www.shenlanguage.org/Download/download.html)

Plain old-style Lisp code.

There are not many modern Lisp books. If you look at PAIP, that is old-style.
PCL is more modern. But neither has the look or feel of Clojure.

But I'm not saying that Lisp's don't contain new stuff. I'm saying that they
contain the old stuff + new stuff.

Clojure gets rid of core old stuff:

* names are different

* concepts are removed (mutable cons cells, ...)

* syntax is different from every other Lisp

* semantics is different (persistent data structures, ...)

> By "persistent" Clojure means "immutable"

immutable and persistent are different, but related concepts. A data structure
can be immutable, but it does not need to be persistent. 'Persistent' means
that an immutable data structure can be updated, keeps all its versions and
provides certain performance/space characteristics (one does not do full
copies for example).

Imagine a list (f o o b a r). Now I want to insert 1 between f o o and b a r.

Immutable: I need to make a new list with elements from the old list copied.

Immutable and Persistent: I make a new list, but I possibly reference parts of
the old data structure. Thus I don't need to make a full copy.

Lisp's lists/vectors/... are not immutable and also not persistent.

Clojure replaces that. Just read
[http://clojure.org/sequences](http://clojure.org/sequences)

~~~
kragen
Some Clojure sequences are lazy, but Clojure lists aren't. And you are right
that there's a typing constraint that prevents you from making improper lists,
and that's not the traditional behavior of Lisp conses.

As for the 1960 code in the manual, no, that wasn't the source code used by
the first Lisp implementation.

In the Shen case, I assume you're talking about things like this, in
primitives.lsp?

    
    
        (DEFUN eval-kl (X) 
          (LET ((E (EVAL (shen.kl-to-lisp NIL X))))
              (IF (AND (CONSP X) (EQ (CAR X) 'defun))
                  (COMPILE E) 
                  E)))
    

What I see here:

    
    
        - Indentation to show structure;
        - DEFUN;
        - ';
        - IF;
        - LET;
        - some lowercase letters.
    

To me, that looks a lot like the modern Clojure code, and not much like the
1962 code.

Your taxonomy of immutability and persistence is interesting; thank you. I
thought you might have meant that Clojure lists were automatically serialized
to stable storage on, for example, program exit. Lisp lists have always been
persistent, then, except when you mutate them? Because you can make your (f o
o 1 b a r) from (f o o b a r) without copying the whole thing in any Lisp.

Lots of Lisps have been backwards-incompatible with previous Lisps. Scheme,
Common Lisp, Emacs Lisp, and even MACLISP and LISP 1.5 were all significantly
backwards-incompatible with their predecessors. That didn't make them non-
Lisp. Common Lisp was not the end of Lisp development.

~~~
lispm
> Lots of Lisps have been backwards-incompatible with previous Lisps. Scheme,
> Common Lisp, Emacs Lisp, and even MACLISP and LISP 1.5 were all
> significantly backwards-incompatible with their predecessors.

Right. That's what I'm saying. Clojure does not care to be backwards
compatible with Lisp.

> Your taxonomy of immutability and persistence is interesting

That's not mine.

Clojure took its base data structures from Haskell and modern ML.

Not Lisp.

See:

[http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf](http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf)

[http://en.wikipedia.org/wiki/Persistent_data_structure](http://en.wikipedia.org/wiki/Persistent_data_structure)

The book comes with examples in ML and Haskell.

[http://www.amazon.com/Purely-Functional-Structures-Chris-
Oka...](http://www.amazon.com/Purely-Functional-Structures-Chris-
Okasaki/dp/0521663504)

~~~
kragen
I don't think we're going to get anywhere further in this conversation,
although I really appreciate everything you've posted so far, and I heartily
second your recommendation of Okasaki's book, even though I haven't finished
it myself. And I hope that I have avoided being anything like Erik Naggum in
this conversation, despite my frustrations.

~~~
sillysaurus
This conversation was _incredible_!

------
danielparks
I asked on the author’s site as well, but I don’t understand the argument that
JavaScript doesn’t have lexical scoping.

[http://c2.com/cgi/wiki?LexicalScoping](http://c2.com/cgi/wiki?LexicalScoping)

~~~
cobbal
It probably refers to the fact that variables by default are global. If you
prefix them with var they're function scoped, but there's no way to make them
local to the curly braces of an "if" statement.

In scheme, lexical scoping is easily accomplished through the let form, and
it's pretty hard to make a variable global by mistake.

So yes it does have lexical scoping in the sense that function arguments are
lexically scoped, but that's the only scoping environment, and you can't hide
that fact behind macros like you could in scheme if it was needed.

~~~
mistercow
>If you prefix them with var they're function scoped, but there's no way to
make them local to the curly braces of an "if" statement.

There is; it's just ugly. You just have to use an immediate function as the
body of the if statement.

~~~
djKianoosh
in the words of will smith in men in black, "please keep that kinda shi* to
yourself"

~~~
mistercow
I don't understand what you're trying to say, but I was describing a common
and useful pattern.

~~~
djKianoosh
i was complimenting you.. ahh nevermind

------
kragen
On one hand, it's true that Scheme has a lot of things JS doesn't, and vice
versa; and the feel of the languages is very different. On the other hand,
it's completely clueless to claim JS doesn't have lexical scoping. Only
someone who didn't understand what the alternatives to lexical scoping were
could claim that.

~~~
gsg
Quite the contrary. Javascript has a strange, ugly hybrid of lexical and
function scope that is not that of Scheme, which I suspect that Bob
understands very well given his interest in languages (and that he works on a
language that compiles to JS).

This is not lexical scoping:

    
    
        function example(k) {
            function ugly() {return i};
            for (var i = 0; i < k; i++) {}
            return ugly;
        }
        example(4)() // => 4

~~~
kragen
Yes, the scoping in your example is lexical. That's why ugly returns k
regardless of where you call it from; we can reason lexically to show that.

The i in ugly is lexically resolved to refer to a particular declaration, the
one on the line below it. Scheme's lexical scoping rules are not the only
possible lexical scoping rules. A lexical scoping system does not cease to be
lexical simply because it is not the same as Scheme's lexical scoping. For it
to be non-lexical, the scoping would have to depend on something other than
the lexical structure of the program. For example, you could just as well have
a dynamically-scoped JS in which ugly's return value would depend on its
caller's binding for i, and in which calling a function with a free i from
within example would make example's binding for i visible to that other
function, but that isn't the way JS works.

It's quite reasonable to argue about whether that scoping is _sane_ , and
indeed with "let", the ES folks are giving us a saner binding construct; but
it is certainly the case that the relationship between the declaration and the
use of a variable is established by the lexical structure of the program text,
not the dynamic structure of the executing program.

~~~
untothebreach
The "WAT" for me is that the `var i` is hoisted _out_ of the `for`, which
IMHO, breaks the principle of least astonishment. I would expect the `i` to be
lexically scoped to the body of the `for` block, instead of being hoisted out
into the parent scope of the `for` block.

~~~
iopq
I speculate that this is because Javascript takes stuff from Self where loops
are functions.

So probably Javascript was meant to write something like: while(function(k) {
++i; return i < k; });

where the while function would call the closure until it got false at which
point the while function itself would return so having var declarations be
hoisted was not a problem in this syntax because everything (including if and
while) would have its own scope due to being a function

~~~
kragen
You could have designed a language like that, but Brendan didn't.

------
jliechti1
Part 1 of Douglas Crockford's _On JavaScript_ gives a really nice history of
the many programming languages leading up to JavaScript.

 _Chapter 1: The Early Years_ :
[http://www.youtube.com/watch?v=JxAXlJEmNMg](http://www.youtube.com/watch?v=JxAXlJEmNMg)

 _Chapter 2: And Then There Was JavaScript:_
[http://www.youtube.com/watch?v=RO1Wnu-
xKoY](http://www.youtube.com/watch?v=RO1Wnu-xKoY)

~~~
scrabble
I was thinking the same thing while reading the article.

JS has inherited from both Scheme and Self.

------
DanWaterworth
Haskell doesn't have first-class continuations, it has syntactic sugar that
allows you to write continuation passing code in a direct style.

------
bwy
This is absolutely insane. I don't even know how it got to the point that an
article was necessary to explain this.

~~~
pjmlp
I started coding in a Timex 2068, back in 1986, I keep getting surprised with
one needs to explain nowadays to youth generations, given the amount of
available information about computing in general.

------
etler
This article is based on the assertion that there are people that think
Javascript is Scheme with an ugly makeover. But do those people exist? Most
people who make the comparison aren't saying they they're equal to each other,
but that they share similarities. Maybe some people hear that out of context
and take it too far, but I don't think they're the majority.

I think the thing that makes the comparison is more the first class functions
than the closures. The closures assist the first class functions, but the
functions are the star.

Not a whole lot of non functional programming languages support first class
functions with the simplicity and completeness of javascript.

[http://en.wikipedia.org/wiki/First_class_function#Language_s...](http://en.wikipedia.org/wiki/First_class_function#Language_support)

In javascript, passing functions as parameters is a day to day thing, and that
style of being able to pass around different functions as building blocks is
what gets it compared to functional languages. Sure, that's not the only thing
that functional languages have going for them, but it's the most important
thing, and what they're even named after.

------
bhashkarsharma
Very well and funnily written, among other things. Thoroughly enjoyed :)

~~~
hobs
Couldnt agree more, the writing style of the author is amazing(especially
considering the topic). The use of humor to make what could be a dry subject
pretty damn good is a rare talent.

~~~
munificent
Thank you! I try very hard to make it worth the reader's time to read it.
Humor and interesting phrasing is a big part of that.

~~~
hobs
I am glad you saw that, me and a coworker were discussing how you should keep
on blogging, good work!

------
jrochkind1
It's true because it's funny.

------
skyhvr
Beautiful.

------
dschiptsov
JS might look like Scheme (can't imagine what shall I smoke) only to those,
who never managed to learn the later.)

But people like to repeat slogans without understanding. This is how everyone
is calling Clojure a Lisp, for example, while it is a language of its own,
which happen to use parenthesized syntax.)

It is not parenthesis that makes a language Lisp. It is not first class
functions that makes it Scheme.) Lisp/Scheme is a set of conventions/features,
and when some are broken and other are missing that means it is something
else.

~~~
hkolek
I agree, but I'm wondering what you think is missing or broken in Clojure to
prevent it from being a Lisp? Sure, it sits on top of the Java type system and
one major thing I can think of that is lacking is the condition system
(although, isn't this a only Common Lisp thing?). I don't think it has to be
Lisp all the way down to be a Lisp dialect, if that's what you're getting at.

~~~
anonymoushn
Every other Lisp happens to have TCO, so if you try to port other Lisp
programs to Clojure you generally get stack overflows.

~~~
hkolek
But afaik TCO is only a requirement for Scheme implementations, not for e.g.
Common Lisp (i.e. you don't need to implement TCO to satisfy the Common Lisp
standard). I don't see how the lack of TCO prevents it from being a valid Lisp
dialect.

~~~
cgag
Do you need to implement the common lisp standard to be "a lisp"? What is a
lisp?

~~~
hkolek
Exactly my point. I was just using CL as example because I think it would be
hard to argue that it is not a Lisp yet the standard doesn't guarantee TCO.

> What is a lisp?

It's a very good question. I think PG sums it up quite nicely in "Revenge of
the Nerds" [1]. Although, now that I'm thinking about it, I'm not quite sure
there's any point in classifying something as a Lisp or not...

[1] [http://www.paulgraham.com/icad.html](http://www.paulgraham.com/icad.html)

