
Smalltalk vs. Scheme, JavaScript, and Java - horrido
https://medium.com/smalltalk-talk/smalltalk-vs-scheme-javascript-and-java-e031fa6d3528
======
Lordarminius
Another acerbic article from Richard Eng critiquing javascript.

Granted that javascript is inconsistent and poorly designed. But what does he
expect a beginner programmer to do? Learn a language has neither widespread
acceptance nor community support, in an attempt to get away from javascript's
deficiencies?

Even Google could not wean sophisticated programmers (who appreciate the
issues way better than I and many others do) away from javascript despite its
incredible efforts.

I for one am interested in getting the job done quickly and as painlessly as
possible. I dont make the tools I just use them.

Thoughts anyone?

~~~
throwaway7645
All good points. Personally, its an idealism versus practicality argument. I
personally believe (take this with a grain of salt) that we should deprecate
awful languages like JS if there is truly a better alternative out there that
gives superior power, ease of use, and safety. The economist in me points out
that this would've already happened had they really been that much better.
Kind of like one-hit wonders like "ice-ice baby" are actually not crappy songs
but amazing works of art according to the masses. Maybe one day P6 will get
optimized and polished enough to where all users of (P5, Python, Ruby, and
TCL) say "I want that" and switch. Individuals might do that. Companies are
more like glaciers.

~~~
dri_ft
I don't think whether or not it happens (or has already happened) depends
solely on whether the other languages are better. Isn't it a lot of it a co-
ordination problems? People want to write in the languages that are widely
used and have a lot of libraries; people write libraries for languages that
are already widely used; that sort of thing?

You're right about Ice Ice Baby, though.

~~~
dgreensp
I see it as popularity vs merit. A lot of things feed into popularity, like
familiarity and network effects. Also, you can be popular by appealing to the
sentiments or taste of the masses or influencers, regardless of merit, unless
there are strong corrective market forces.

------
qwertyuiop924
To the contrary, Scheme's prefix notation reads quite well, particularly if
you use indentation well. But that's just my opinion.

Several of the statements in this article about Scheme are, however,
objectively wrong.

-Scheme isn't functional. It makes no effort to control side-effects, and a lot of Scheme is heavily stateful. In fact, the very Scheme example you wrote isn't functional at all!

-Scheme isn't uncomfortable for OO. Multiple OO frameworks have been written in Scheme (most of them based upon CLOS), and many of them are very comfortable and quite excellent. If you don't like multiple-dispatch functions, it's also possible to implement smalltalk-style object-message syntax (and indeed, people have done so).

In fact, if you look into the history of Scheme, it was orginally written by
Sussman and Steele to help them understand the Actor Model, which is quite
similar to OO: a program is modeled as many stateful actors, which can only
communicate through messages.

Finally, the "confusing" Scheme code in this article is not very well written.
If you split the definitions like so, it becomes much more readable (also,
vector-map! is already defined in many schemes, so you don't even have to
evaluate the top part):

    
    
      (define (vector-map! f v)
        (do ((i 0 (+ i 1)))
            ((= i 0) v)
          (vector-set! v i (f (vector-ref v i)))))
    
      (define (make-matrix rows columns)
        (vector-map! 
          (lambda (a) (make-vector columns)) 
          (make-vector rows)))
    

Again, there are several common extensions (in various SRFIs) that would make
this even cleaner. In the upcoming R7RS-large (the Red standard, which has
these functions, has just been released), I would merely need to import one
library, and vector-map! would be defined for me, as is already true in many
implementations.

~~~
nickpsecurity
I don't think it reads well. I came from ALGOL family as you'd expect. I
always hated LISP syntax unless I was doing a parser or 4GL. LISP lovers have
always acted like it's impossible to give in on this point to increase
adoption whereas some had saner strategies:

[https://en.wikipedia.org/wiki/Dylan_(programming_language)](https://en.wikipedia.org/wiki/Dylan_\(programming_language\))

Much more beautiful to read. You could almost turn syntax that looks like that
into a scripting language with a good standard library. Would probably get
widespread, commercial and FOSS adoption plus make Hacker News a lot. Just
speculation on my part over ten years ago. Maybe give it a cute-looking, snake
logo to symbolize making people like something they hate.

Nah, I'm sure lispers will miss this obvious strategy for success of their
favorite language. :P

~~~
qwertyuiop924
I do get your point, Nick, but I'm not sure I agree. Dylan, Nim, and other
programming languages that try to have Lisp's macro facilities (which are the
main reason we stick to the sexpr code format) may be nice to program in, but
they're am absolute pain to metaprogram in. Just look at Nim's procedural
macros, for crying out loud!

Also, many of us lispers like the regularity and simplicity of syntax that
sexprs allow (no syntax, no precedence).

OTOH, a more direct sexpr mapping might work, a la wisp.

Seriously, if your main object to lisp is the syntax, wisp may be something
you want to try.

~~~
nickpsecurity
Another thing to consider is how often people need to write macros. The vast
majority of programmers will just use base language and libraries. The
libraries contain the macros. Advanced programmers can create the macro
libraries. This provides the massive benefit on adoption for regular
programming without the drawback of metaprogramming. Further, the macro
language might even use s-expr syntax that prettier language is converted to
in first pass of parsing. So, instead of paren language as default, it's an
ALGOL-like language as default with syntax extensions or mods being made for
macro work. In reverse of of lispers normally do it.

Re WISP. Looks better but still prefix. The prefix notation is the problem as
it's designed to be easy for computers & compiler writers, not humans reading
it.

~~~
qwertyuiop924
Yeah, that's closer to the WISP model, which works well, as opposed to what
Dylan and Nim did.

As for the lack of infix in WISP, IIRC WISP supports use with SRFI-105 (a part
of another project to introduce a different syntax to Scheme, SRFI-110, aka
readable), which provides exactly this.

------
throwaway7645
Interesting how he critiques something cryptic in Scheme and doesn't show the
Smalltalk equivalent. One thing that should have its own full section is
performance as it is slower than Java, compiled Scheme, and I'm guessing V8
optimized JS. I know the whole hotspot JIT thing was maybe pioneered in
Smalltalk though? I do like certain things about Smalltalk (Pharo looks nice),
but it is hard to do certain things with it like a GUI. Well I mean it is hard
to find out how to do that....not necessarily hard to implement.

~~~
chriswarbo
> I know the whole hotspot JIT thing was maybe pioneered in Smalltalk though?

As far as I'm aware the ideas used in hotspot began with Self[1], which was
also the inspiration for Javascript's prototypical inheritance. Strongtalk[2]
adapted these to the class/instance programming style of Smalltalk, then Sun
bought them for application to Java.

[1]
[https://en.wikipedia.org/wiki/Self_(programming_language)](https://en.wikipedia.org/wiki/Self_\(programming_language\))

[2]
[https://en.wikipedia.org/wiki/Strongtalk](https://en.wikipedia.org/wiki/Strongtalk)

~~~
throwaway7645
I stand corrected thanks!

------
zengid
>>[Smalltalk is] the perfect instructional language for teaching programming
to both children and adults alike. It’s very easy to learn and extremely
versatile...

Where's the data to support this? Has anyone done a randomized double-blind
study on new programming students using smalltalk vs groups using Scheme, JS,
or Java? Why is someones biased opinion enough to justify this claim? We need
to hold ourselves to a higher standard than to accept unsupported arguments
(meaning they havent been tested empirically) [1].

[1]
[https://www.youtube.com/watch?v=uEFrE6cgVNY](https://www.youtube.com/watch?v=uEFrE6cgVNY)

~~~
agumonkey
Just curious, have you learned ST ? I went through a good deal of languages
and I have to admit, ST surprised me more than expected and mostly positively.

I don't like the smug some STers glow when they talk about REALOO but except
that it really has some exceptional qualities (self consistency, humane
interface, small size of the basic system).

~~~
zengid
I haven't learned ST yet but look forward to someday; currently I'm learning a
bit of Ruby. I don't doubt that it is an excellent language, but is it
_actually_ easier to learn without any prior programming experience, or is
that claim it just based on opinions?

~~~
agumonkey
I don't know any methodical study, so it may only be opinions. That said,
after suffering years of bad language features, you feel weird when one
actually delivers on some bold claims. Smalltalk is not even a language, it's
a system, a self contained system that is quite small, consistent, yet somehow
devoid of ceremony (FP languages are small, but one has to read through the
culture, ST stay low in intellectualization). I don't see many of the things
that tripped me up as a noob, and lots of stuff that I ended up seeing as
valuable (how booleans are defined for instance).

------
webwanderings
Since it is addressing beginning programmers, I would like to add my take. I'm
not a programmer but I have many years worth of computer experience.
Programming never appealed to me because it never came naturally.

Lately I (once again) started paying attention to programming and started
looking around. I went from one e-book and MOOC to another with much of the
python hype (previously in my - failed - attempt, I tried Perl, PhP etc, when
they were in vogue). Well I have eventually concluded, that the problem with
programming is not necessarily me, but it is the lack of proper padagogy
itself. There are programmers galore out there trying to teach via YouTube and
MOOCs, but most are code monkeys who know what they're doing but I wouldn't
call them "teachers".

So my search eventually led me to Scheme/Racket where I see some signs and
hope of proper learning (I'm not going to be able to afford myself to take a
college level CS). I looked into Small Talk as well but as of now I don't see
a proper MOOC on it. I have started Racket course (BSL) on EdX. After spending
much time and energy chasing Python basics and going nowhere, i feel I can
possibly and eventually learn programming the way it is meant to be.

~~~
horrido
Try this Pharo MOOC:
[http://files.pharo.org/mooc/](http://files.pharo.org/mooc/)

The actual course is over, but all the course material is still available.
It's an excellent resource.

~~~
webwanderings
It's in French; adds a second level of difficulty due to language difference.

~~~
horrido
The material is available in both French and English. The videos have English
subtitles. There is no language difficulty.

------
dgreensp
I see mostly criticisms unrelated to SmallTalk.

Scheme: Show me the code comparison. How is FP vs OOP relevant, even if true?

JavaScript: How is the comparison to Lisp relevant, especially after the
preceding? Author just chose some appealing praise of JavaScript to tear down.

Java: This reduces to an argument you should consider SmallTalk at all for
systems programming.

------
allengeorge
I found the critique unconvincing, especially since I don't see any Smalltalk
examples in the article to support his position. Not I that I doubt there are
languages better than both JavaScript and Java.

------
throwaway7645
I think a lot of his points still stand though with ST being elegant in a lot
of ways and relatively easy to learn.

------
sebringj
Please don't format code with ))))))) at the end for the love of code! Use
readable indentation instead as your whole point is to make things look simple
to understand. That actually warrants a slap the back of your head from a team
of onlookers, one at a time.

~~~
actsasbuffoon
Once you look at enough of it, your brain starts to see lisps differently. The
parens fade away, and you mostly just see the indentation. It looks a little
like Python once you adjust.

~~~
horrido
You're over-generalizing. This is very much a matter of personal
taste/inclination. Do ALL Lispers love the Lisp style of syntax? Of course
not.

Moreover, for many programmers, it's asking too much of them to wrap their
heads around a syntax where you need to give it time for the parens to "fade"
away. This cognitive hurdle is real and it's why Lisp isn't more popular.

Let's not bury our heads in the sand.

~~~
lispm
It's not just the parentheses. It's the whole code-as-data and interactive
development thing. Code is different. Programming is different.

Lisp uses different working styles and tools. You have to learn the whole set.
It's possible to learn that and to learn it well, but it might take some time.

Lisp code can be very readable, but it's also to write very complex code -
more complex that in most languages, since Lisp provides many mechanisms under
developer control.

~~~
kazinator
Even if you don't care about using code as data, Lisp is simply more readable,
period.

You don't have to crack open a reference manual to look at grammar rules or
precedence tables to work out what the shape of the syntax tree is; you can
read anything just from the symbolic prefix, plus a smattering of minor
notations like sharpsign-this and sharpsign-that.

A programmer who doesn't know Lisp can still instinctively tell that in (foo
(x y) (z w)), the x and y go together more tightly than foo and x, or y and z.

The meaning is determined by foo. But foo is a word. And words have the nice
property that you can look them up easily in manuals (potentially with just a
mouse click).

Those who say Lisp is not readable are trolls and liars. They are liars
because they see it's obviously more readable, but it threatens their self-
image of being a competent programmer. It does that because their self-image
is rooted in having memorized a bunch of arcane syntax and believing that that
is what makes a software developer.

Look at this comment, for instance:

[https://news.ycombinator.com/item?id=12883362](https://news.ycombinator.com/item?id=12883362)

 _" If only the LISP syntax looked like a programming language and made
logical sense."_

Very good representative comment which captures the mindset aptly.

A programming language can only possibly be legit only if programs in that
_look like_ what you already know.

~~~
lispm
> You don't have to crack open a reference manual to look at grammar rules or
> precedence tables to work out what the shape of the syntax tree is; you can
> read anything just from the symbolic prefix, plus a smattering of minor
> notations like sharpsign-this and sharpsign-that.

You can't. Any macro may support arbitrary syntax. If all you know is the
macro name, you don't know nothing about the syntax it implements.

> (foo (x y) (z w))

There are many many much more complex forms in Lisp.

> And words have the nice property that you can look them up easily in manuals

Then you have to read the syntax FOO implements.

DEFGENERIC:

    
    
        defgeneric function-name gf-lambda-list [[option | {method-description}*]]
    
        => new-generic
    
        option::= (:argument-precedence-order parameter-name+) | 
                  (declare gf-declaration+) | 
                  (:documentation gf-documentation) | 
                  (:method-combination method-combination method-combination-argument*) | 
                  (:generic-function-class generic-function-class) | 
                  (:method-class method-class) 
        method-description::= (:method method-qualifier* specialized-lambda-list [[declaration* | documentation]] form*) 
    

Then you need to know the set of precedence order names. What is a GF-
DECLARACTION? What is a method-qualifier? what is the specialized-lambda-list?
What are valid declaration expressions...?

> Those who say Lisp is not readable are trolls and liars.

I don't think you add credibility with these statements. Sorry, this is just
dumb.

~~~
kazinator

      (defgeneric draw (thing on-what where))
    
      (defmethod draw ((obj drawable) (where canvas) (location point))
        ...)
    

No brainer.

Even though macros can contain any syntax, and in principle we can have a
macro such that:

    
    
      (mac token1 token2 token3 ... tokenN)
    

where the tokens are parsed according to some LALR(1) (or worse) grammar, in
practice, macros are usually not designed that way. The nested list syntax is
used for grouping units together.

So without knowing what mac is, you don't know the semantics, but the
structure is, more often than not, crystal clear.

Of course you need the manual to know what they mean if you don't remember
(gee, which is the class name and which is the instance, location or point?),
but you don't have to implement the LARL(1) parser in your head.

~~~
lispm
Here is an exercise for you:

Which of the following forms are valid Common Lisp:

    
    
        (defun foo (a b)
          (declare (fixnum a))
          "foo"
          (declare (fixnum b))
          (+ a b))
    
        (defun foo (a b)
          "foo"
          (declare (fixnum a))
          (declare (fixnum b))
          (+ a b))
    
        (defun foo (a b)
          (declare (fixnum a))
          (declare (type fixnum b))
          "foo"
          (+ a b))
    
        (defun foo (a b)
          (declare (type fixnum b))
          "foo"
          "bar"
          (declare (fixnum a))
          (+ a b))
    
        (defun foo (a b)
          (declare (fixnum a))
          (declare (type fixnum b))
          "foo"
          "bar"
          (+ a b))
    
        (defun foo (a b)
          (declare (fixnum a))
          "foo"
          "bar"
          (+ a b))

~~~
kazinator
I don't know, and who cares.

I seem to be vaguely convinced for some reason that there may be exactly one
docstring, and that, if present, it must be the first item in the body; then
there can be declarations. Not sure if there can be two or more declares. I
would always write (declare (fixnum a) (fixnum b)) and don't recall seeing
multiple declares in other people's code. (I might be suffering from a form of
amnesia which merges multiple ANSI Lisp declares into one.)

This is the sort of thing I'd look into closely if I were tasked with parsing
a function body (like for the sake of making some body rearranging-and-
reassembling macro fully conforming with the surrounding language). I'm not
going to write such code myself, and won't likely see it in other people's
code.

Until I see such instances, I won't bother looking at the spec to see what the
exact rules are and confirm/refute whether those examples are conforming.

In any case, whether or not some of the examples are correct, I can see what
they are _trying_ to say. Be they mistakes, they are still well-formed surface
syntax and are readable. Things could plausibly work in some CL dialect such
that they are all correct, if they aren't.

A literal string near the beginning of a function, which is only evaluated for
its side effect (which it doesn't have) looks suspiciously like a doc string.
Either it is correctly positioned or it isn't. The (declare ...) syntax is
clearly a declaration, whether or not correctly positioned. (declare ...)
isn't a form. I suspect it would be undefined behavior for a program to define
a function or macro called declare; not sure about that. Defined or not, it
would be a incredibly bad idea.

I'm a competent Lisp programmer and implementor too, and don't have to have
this memorized; it's likely not an impediment to anyone else. Which kind of
makes my point.

~~~
lispm
> I don't know, and who cares.

A Lisp programmer has to care, if he wants to write Lisp code.

> I seem to be vaguely convinced for some reason that there may be exactly one
> docstring, and that, if present, it must be the first item in the body

That's wrong.

> I won't bother looking at the spec to see what the exact rules are

Which confirms what I'm saying: even for seemingly trivial DEFUNs the syntax
is not obvious.

> Be they mistakes, they are still well-formed surface syntax and are
> readable.

But the reader does not implement Lisp syntax. The reader just implements
s-expression syntax. If the reader can read the form, then it is a valid
s-expression. But not necessarily valid Lisp.

    
    
         (defun foo (a) a)  ; valid s-expression, valid Lisp
         (defun (foo) a a)  ; valid s-expression, not valid Lisp
         (defun (bar foo) (a) a)  ; valid s-expression, not valid Lisp
         (defun (setf foo) (a) a)  ; valid s-expression, valid Lisp syntax
    
         (defun foo (&key a &optional b) (list a b))  ; not valid Lisp
    
         (defun foo ($key a &optional b) (list a b))  ; valid Lisp
    

The Lisp interpreter/compiler and the macros implement Lisp syntax. Not the
reader.

> it's likely not an impediment to anyone else.

That you don't know the syntax of DEFUN confirms what I'm saying: the syntax
is non-obvious.

Explain this:

    
    
        * (defun foo (a b)
              (declare (fixnum a))
              "foo"
              "bar"
              (+ a b))
    
        debugger invoked on a SIMPLE-ERROR: duplicate doc string "bar"
    
        Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
    
        restarts (invokable by number or by possibly-abbreviated name):
          0: [ABORT] Exit debugger, returning to top level.
    
        (SB-INT:PARSE-BODY ((DECLARE (FIXNUM A)) "foo" "bar" (+ A B)) T NIL)
        0]

~~~
kazinator
> _That you don 't know the syntax of DEFUN confirms what I'm saying._

Yes, it rather confirms that you can go far in Lisp without memorizing stuff
like this!!!

If I don't have to know, few people do.

You can bet your ass that if I had to implement an ANSI-CL conforming
defun/lambda I'd get it right, of course. I don't have some "requirements
don't matter" attitude; but not _all_ requirements matter _all_ the time to
_all_ people.

I'd like to add, though, this: you can't be safe in ignorance in Common Lisp.
Things you don't know can hurt you. Less than in some other languages, but
they are there. You probably won't be hurt by not knowing all the
possibilities for combining docstrings and declares. But if you're ignorant of
some things, you may get burned. Undefined behavior situations like modifying
literal tree structure, or writing a program that parses untrusted Lisp data,
not knowing about the #. syntax and * read-eval* . I'm not advocating unsafe
ignorance. Not knowing the full flexibility of some syntax is generally safe,
though.

> _Explain this:_

Which aspect of that error scenario isn't self-explanatory; what is left to
explain?

From that one error, the listener has just taught us several important facts
about the syntax which it accepts (which may be a superset of ANSI CL for all
we know). It shows us that it accepts a docstring _after_ a declare just fine,
but that there must be at most one docstring. (At least, when the two are in
that order, if we are to be strict in our guessing.)

So without looking at a shred of documentation outside of that error message,
I'm already better informed.

The interactive nature of Lisp teaches! (Especially if the implementation is
tight on error checking and has good diagnostics.)

What's left unsettled from that error situation is whether or not there may be
multiple declares, since that case isn't being probed.

~~~
lispm
> Yes, it rather confirms that you can go far in Lisp without memorizing stuff
> like this!!!

That you don't know the relatively trivial syntax of DEFUN, shows that it is
already non-obvious and you have to look it up.

You have failed to explain the syntax of DEFUN and you can't distinguish valid
from invalid forms. I would never trust a code review done by you.

> You can bet your ass that if I had to implement an ANSI-CL conforming
> defun/lambda I'd get it right, of course.

Maybe. Maybe not.

> Which aspect of that error scenario isn't self-explanatory; what is left to
> explain?

Is that valid or not, given the syntax of Common Lisp? Does SBCL implement the
syntax correctly or does it reject valid programs?

The syntax of DEFUN is:

    
    
        defun function-name lambda-list
          [[declaration* | documentation]]
          form*
    

Which says: any number of declarations and at most one documentation, in any
order.

    
    
        (defun foo (a b)
          (declare (fixnum a))    ; declaration
          "foo"                   ; documentation
          "bar"                   ; form
          (+ a b))
    

Which indicates that SBCL rejects a valid program. I would not trust you to
get it right as an implementor, given that you haven't even tried to verify it
and that you are ignorant to Lisp syntax. I would not trust my own
implementation without trying to come up with an extensive syntax test suite.

Similar:

    
    
        (defun foo () "a")           ; sbcl valid
        (defun foo () "a" "b")       ; sbcl valid
        (defun foo () "a" "b" "c")   ; sbcl rejects

~~~
kazinator
Hi lispm. I investigated this more deeply and I'm afraid I cannot conclude
that SBCL is wrong.

The root of the problem is this splicing [[ ]] extended BNF notational
concoction, in whose description we find this:

 _... For example, the expression_

    
    
      (x [[A | B* | C]] y)
    

_means that at most one A, any number of B 's, and at most one C can occur in
any order. It is a description of any of these:_

    
    
      (x y)
      (x B A C y)
      (x A B B B B B C y)
      (x C B A B B B y)
    

_but not any of these:_

    
    
      (x B B A A C C y)
      (x C B C y)
    

_In the first case, both A and C appear too often, and in the second case C
appears too often._

In the case of defun, we can identify C with _documentation_ and y with
_forms_. But _documentation_ is a kind of form. According to the above, if we
are given _documentation documentation form_ , it doesn't match:
_documentation_ appears "too often". That appears to rule out "foo" "bar" as
ill-formed, if "bar" is interpreted as _documentation_ rather than _form_.

This is woefully badly specified; it is not clear how to unambiguously
determine the _extent_ of the symbols matched by a given [[ ]] notation.

There needs to be a clearly stated requirement that [[ ]], independently of
what follows it, denotes (say) the longest possible sequence of symbols which
is consistent with its constraints. The material which follows [[ ]] must then
match against the remaining symbols in the form. Then it will be clear that
given "foo" "bar", the "bar" string isn't part of the [[ declare(star) |
documentation ]] spec, because the longest match ends with "foo" (if no
declares follow).

Maybe it does. I'm afraid I cannot make head or tail out of the sentence _"
such that if n /=m and 1<=n,m<=j, then either Oin/=Oim or Oin = Oim = Qk,
where for some 1<=k <=n, Ok is of the form Qk {star} . Furthermore, for each
Oin that is of the form {Qk}1 , that element is required to appear somewhere
in the list to be spliced. "_ Perhaps that rescues it somehow.

