
JavaScript Isn't Scheme (2013) - tosh
http://journal.stuffwithstuff.com/2013/07/18/javascript-isnt-scheme/
======
dahart
previous discussion
[https://news.ycombinator.com/item?id=6068360](https://news.ycombinator.com/item?id=6068360)

* I'd be curious to hear if @munificent has changed his mind about this article at all since it was written.

Since 2013, JS has added optional lexical scoping and continuations
(promises). There is arguably a distaste for mutation in the community and
among the major JS frameworks, not sure if that counts.

~~~
mst
Promises and generators are both awesome, but they're both way more
restrictive than call/cc. Now, I tend to the idea that that's usually a
feature - and that at most strictly delimited continuations is more than
sufficient in a normal language - but equating promises to continuations is
... not really accurate.

(but oh gods 'let' makes me so happy, having to get sensible closure behaviour
by typing out let-over-lambda shenanigans by hand was -ing horrible)

~~~
Roboprog
Re: “let”

Some might argue that a function which is so long that it needs block scoping,
whether for visibility or storage lifetime management, is too long.

I guess it’s at least “mostly harmless”, though :-)

(“class” arguably sucks in ES2015)

~~~
mst
Being able to write:

    
    
        for (let x in list) {
          callbacks.push(function () { x+3 });
        }
    

instead of:

    
    
        for (var x in list) {
          callbacks.push((function (x) {
            function () { x + 3 }
          })(x);
        }
    

is a huge advantage to me. (yes, I know arrow function notation exists, but
given I was explaining "why I love let" it would've been unfair to use it in
the "good" example)

~~~
Roboprog
Oh. I guess I don’t use for...in much (at all). I see your point now, though.

OTOH:

    
    
        list.forEach( function( x ) {
            callbacks.push( function () { return x + 3 } )
        }
    

I guess I tend to use forEach, or one of the Ramada.js operations, rather than
for loops these days.

EcmaScript isn’t Scheme, or Smalltalk/Self, or Ruby. But it sucks a lot less
than the other language I’m allowed to use at work :-)

(I pretend that ES is mostly Ruby)

------
tomxor
There are some gems in here :D

> Imagine being a construction worker surrounded by big burly dudes, arm hair
> fluttering in the winds of their swinging hammers. And you’re there pushing
> in nails using this ragged spit-stained blankey you’ve had since you were a
> kid. It’s embarrassing, despite the fact that your blanket does actually get
> those nails in. Somehow.

This actually made me laugh out loud (And i'm a full time JavaScript
developer).

~~~
edem
Me too! Another favorite just below that is this:

> You feel insecure, a bit of a weakling. You’re a Belieber at a Meshuggah
> show and what you could really use is some street cred.

------
twic
Someone once told me a story that when Netscape wanted to put a programming
language in the browser, they went to ParcPlace (i think) and asked them if
they could have Smalltalk for that purpose. ParcPlace said sure, go ahead, and
it'll be $1000 a seat.

If there was interest in using Smalltalk, it makes a lot of sense that
JavaScript is an attempt at a Self in Java's clothing.

~~~
goatlover
Brandon Eich said he thought he was hired to put Scheme in the Netscape
browser, but management wasn't interested. Meanwhile Sun wanted Netscape to
put Java in the browser, but Netscape wanted their own scripting language, so
they worked out a compromise, with Eich creating Javascript (I think he may
have worked with one of Sun's developers for JS 1.0).

Eich did a podcast on the history of JS a couple years ago. If memory serves
correct, he said that Netscape did try to put Java in the browser alongside JS
and canvas for both to target, but only JS met the deadline.

Netscape was pretty ambitious back in the day. They did have server-side JS
and JS stylesheets. I wonder how far they would have gotten had MS not decided
to get in the browser game.

I don't know about the Smalltalk angle, but that would be very interesting to
hear about.

~~~
lolive
We would still be waiting for XmlHttpRequest :)

~~~
goatlover
Maybe so! And using layers instead of z-index.

------
DonHopkins
Whenever anyone compares JavaScript with Self, I cringe. The name of the
seminal Self paper was "SELF: The Power of Simplicity" [1]. JavaScript totally
missed the boat on simplicity (the entire POINT of Self), and also totally
missed a couple of important features that make Self Self [2]:

1) "prioritized multiple inheritance": Inherit from multiple parent objects:
you can inherit through any number of parent slots in a Self object, not just
one __proto__ or super or whatever, like JavaScript. There are well defined
rules that determine the priority of parents.

2) "dynamic inheritance": Dynamically change which parents you inherit from at
runtime. In Self, changing who you inherit from at runtime is a useful
programming technique, and the VM implements it efficiently (which is why Self
is so interesting and has been so influential). But JavaScript sets the
prototype when you "new" an object, and it stays that way.

Self is simple because there's nothing but objects, all the way down.
Everything is the same kind of object. Nothing is special.

JavaScript does this weird arbitrary thing by using functions as constructors,
and also as prototypes, for no particular reason. Those special constructor
functions should never be called normally, they should always be called
indirectly with "new". And it means you can only have one constructor. So why
the hell are they functions, if you shouldn't ever call them? It's just
another way to fuck up, due to pointless and arbitrary complexity.

Being that weird way doesn't make JavaScript any more powerful or expressive
or efficient, just more complicated, harder to understand, and easier to make
subtle inscrutable mistakes.

JavaScript punted on the important parts of Self at least as much as it punted
on the important parts of Scheme (like call/cc).

However at least there's a perfectly reasonable excuse for not supporting
call/cc if you have to efficiently interoperate with C code, native libraries
and a garbage collector, and the entire system isn't written in pure Scheme.

But there was no legitimate excuse for screwing up the great things about Self
that, if done correctly, would have made JavaScript simpler and cleaner and
more beautiful.

[1] Self: The Power of Simplicity:
[http://www.selflanguage.org/_static/published/self-
power.pdf](http://www.selflanguage.org/_static/published/self-power.pdf)

>Occam’s razor. Throughout the design, we have aimed for conceptual economy:

>• As described above, SELF’s design omits classes and variables. Any object
can perform the role of an instance or serve as a repository for shared
information.

>• There is no distinction between accessing a variable and sending a message.

>• As in Smalltalk, the language kernel has no control structures. Instead,
closures and polymorphism support arbitrary control structures within the
language.

>• Unlike Smalltalk, SELF objects and procedures are woven from the same yarn
by representing procedures as prototypes of activation records. This technique
allows activation records to be created in the same way as other objects, by
cloning prototypes. In addition to sharing the same model of creation,
procedures also store their variables and maintain their environment
information the same way as ordinary objects, as described in Section 4.

[2] Parents are Shared Parts: Inheritance and Encapsulation in Self:
[http://bibliography.selflanguage.org/_static/parents-
shared-...](http://bibliography.selflanguage.org/_static/parents-shared-
parts.pdf)

>This paper describes the inheritance and encapsulation mechanisms we designed
and implemented in one prototype-based language, SELF. Our design is based on
the philosophy that an object’s parents should be treated as shared parts of
the object, and that inheritance should be a simple, declarative way to
maximize the possibilities for sharing. This paper describes two heretofore
unpublished innovations: a prioritized multiple inheritance scheme that
unifies unordered and ordered multiple inheritance, and an object
encapsulation model that provides many of the benefits of class-based
encapsulation in a language without classes. In addition, our inheritance
system supports directed and undirected resends to forward messages to an
object’s ancestors, a unique sender path tiebreaker rule that resolves many
ambiguities between unrelated unordered parents, and dynamic inheritance,
which allows an object to change its parents at run-time to effect significant
behavioral changes due to changes in its state.

~~~
munificent
I wouldn't express in as delightfully salty a way as you have, but I totally
agree that JavaScript is got little from Self beyond the word "prototype",
which it misused.

Self is an incredibly powerful, simple language. I'm still not sure if it's a
_good_ language. My own experiments with prototypes left me feeling like it's
_too_ simple and formless. It felt like building a house out of toothpicks.

~~~
goatlover
Couldn't Lisp be accused of the same thing? I realize that CL has a boatload
of features, but fundamentally Lisp is very simple and formless in using the
list form for all code and data.

~~~
munificent
I think so, to some degree.

My "building a house out of toothpicks" isn't too far from Alan Kay's "Lisp
isn't a language, it's a building material".

I think both Scheme and Self feel like they give you the tools you can use to
build your own language on top of them. Where by "language", I include the
facilities for composing and abstracting code, idioms, best practices, and all
of the other stuff most languages enshrine directly in their semantics. Java
says "the best way to organize code is in classes".

Scheme and Self don't really say anything at that level. They give you the
tools so that _you_ can say what you want. If you want classes, you can build
class systems in Scheme and Self. If you don't, you don't have to.

At one level, that's really cool — I get to be a language designer! But if you
just want to ship and app and be working at the top of the stack, it sucks
when you have to show up on day one and pour the foundation yourself first.

------
chriswarbo
I think of JS as being Scheme-like, but not because of any love for the
language. Instead, whenever I'm using JS I take a Crockford-like approach by
only using a nice subset of the language: basically, closures and not much
else.

When I'm writing JS in this way, my mental model is basically "a crappy
Scheme", i.e. I'll tend to come up with implementations which are similar to
what I'd do in Scheme (pure functions and closures), except I have to
consciously avoid boilerplate (since there are no macros to tame it) and
unbounded recursion (since there's no tail-call elimination), hence the
"crappy".

Maybe it helps that none of my Scheme code has used continuations, outside of
examples/playing, so there's less of a disconnect there?

~~~
edem
I'd suggest using Kotlin then. It has tail call optimization, and nice
functional programming constructs. It can also be compiled to javascript:
[http://the-cogitator.com/2018/04/25/going-beyond-android-kot...](http://the-
cogitator.com/2018/04/25/going-beyond-android-kotlin-on-the-frontend.html)

~~~
chriswarbo
> I'd suggest using Kotlin then

I gave the caveat of "whenever I'm using JS" since I only use JS when I have
to, and that's not very often (as I say, I don't have much love for the
language).

I think it's a bit inappropriate to throw out random suggestions like Kotlin
when the discussion is about Javascript and Scheme. I spend most of my time in
Haskell, which (like seemingly _every_ language these days) can also be
compiled to JS, and I'd wager is 'even more functional' than Kotlin. I didn't
mention it because the discussion was about JS and Scheme ;)

------
edem
Anecdote time: A long time ago I was put on a javascript project. It was a
greenfield one but I had to use js because it was a browser app. I've also
heard this Scheme myth but having worked with Common Lisp I thought that this
must be a mistake. So I took a look at JSON and thought that well json is
homoiconic. The problem is that you don't have a homoiconic syntax for
functions so I tried the eval way but it became ovbious tha this is an ugly
hack at best. I concluded that js has anything to do with scheme.

------
jakear
I really don't get all the JS scoping hate. Especially because its quite
similar to Python in that they both have lexical scoping with functions
introducing new scopes, and I rarely hear complaints about Python. I guess
this scoping might be annoying to people coming from C-style background, but
it's really not all that big of a deal. JS even has `let` now to allow blocks
to introduce new scopes too.

~~~
haskellandchill
Python is awful. Since you haven’t heard any complaints. Maybe 3 is ok, can’t
use it don’t know. Have to use 2.7 at work. Can’t make jars for Spark with
Python and yes I am salty about it. Meanwhile we are on Ruby 2.5.1 because
they didn’t fork the whole ecosystem with a language upgrade.

~~~
chc
Ruby's 1.9/2.0 upgrade had pretty similar changes to Python 3. For example, in
Ruby 1.8.7, 'hello'[1] returned 101, whereas now it returns 'e', and
String#each doesn't even exist anymore. Similarly, string encodings became
significant in both Ruby and Python's breaking changes. It seemed to me like
the Ruby ecosystem just didn't drag its feet as much as Python's (probably
largely because Rails had enough pull to drag the Ruby ecosystem along with
it, and Rails enthusiastically supported Ruby 2).

~~~
mxyzptlk
Matz didn't change puts. It seems trivial, but I suspect making print a
statement again would do a lot to speed up the Python3 adoption rate.

------
zwerdlds
(2013)

~~~
sctb
Thanks! Updated.

