
Three Laws of Programming Language Design - Garbage
http://lambda-the-ultimate.org/node/4754
======
api
Fun to ask these questions of different languages. Here's two I've been using
recently:

\- C++:

What they got right? RAII, ability to code "close to the metal" if you want or
highly abstractly if you don't, templates for powerful code re-use, and a
long-term stable ABI on most platforms. The latter is huge-- it means you can
write code in C++ and actually ship it.

What they got wrong? Variations in syntax between headers and code files (e.g.
~Destructor() vs. Destructor::~Destructor()), weird template edge case hell
that requires 'typename' and 'template' keyword use in unpredictable places,
too much symbol re-use (&, <>, asterisk, etc.) that makes code hard to read
and parse in a misguided effort to not break 0.000001% of existing code.
Pointers are unsafe since you don't know whether something was allocated on
the stack or you should delete it.

What's confusing? A lot, unfortunately. :) Templates are the primary source of
this.

\- JavaScript:

What they got right? It's functional. Really. It's basically a lite weakly-
typed Scheme shoehorned into a Java-like syntax. The language is easy to parse
and simple enough that JITS can be made that run it fast. Functions are first-
class citizens and you can sling them around like any other variable.

What they got wrong? Numeric types are poorly implemented, making the language
unsuitable for "serious algorithm" type stuff. There is no canonical way to
define and extend objects, resulting in conflicting styles across projects.
There is also no builtin way to do sane async code without the "pyramid of
doom" (20-level deep indents). Libraries like async or underscore help, but in
a language that wants to be async as bad as JS this should be _core_. Finally,
the fact that it's a functional language shoehorned into looking like Java
means there are all kinds of confusing syntactic variations that arise when
it's used functionally. function() {} vs x = function() {}; -- note the extra
semi.

What's confusing? Type promotion, weird rules around true/false evaluation,
the == vs === mess, what 'this' means.

~~~
tmhedberg
Scheme (and FP in general) is much more than just first-class functions. If
that's all that is required for a language to be considered functional, then
nearly every modern programming language is a functional language, and the
term becomes essentially meaningless. First-class functions are nothing
special or unique anymore.

FP is also about frictionless _composition_ of functions, declarative rather
than imperative style, use of expressions instead of statements, and very
critically, emphasis on statelessness and immutable data.

JavaScript is anything but stateless--it is extremely awkward, if not
impossible, to avoid mutation in idiomatic JS code. Imperative statements
abound, and everything is a reference, there are really no pure values to be
found. Functions can be composed, but the syntax makes it unintuitive and
ugly. And though it is probably not a hard requirement for FP, most FP
languages at least make an attempt to distinguish pure functions from stateful
procedures, e.g. via types in Haskell, or just naming conventions, as with
Scheme's `set!`, but JS does not really facilitate this in any way.

Functions and lexical closures are undoubtedly some of "the Good Parts" of
JavaScript, but these alone are not sufficient for functional programming. JS
is fundamentally an imperative, OO language which happens to have a very light
dusting of FP flavor on top.

~~~
mrbrowning
Moreover, as far as Lisp dialects go, homoiconicity is a big part of their
identity and a major source of their power. It's an orthogonal concept to
functional programming in general, just look at e.g. Haskell, but that's one
of the first things I think of when I hear the "JS is just an ugly Scheme!"
argument.

~~~
Androsynth
javascript has json though, which doesnt make it homoiconic, but it allows you
to mimic homoiconicity in a lot of cases. When I write in javascript, I tend
to store my data in json and and write code that is generic, with much
abstraction that has a small foot print to manipulate the json.

That is scheme-like. That is psuedo-homoiconic.

(If anyone in the know wants to add or refute this, I would love to know
whether my non-cs intuition is correct here.)

(also it is still a very mutable language, even with coffeescript/underscore)

~~~
andolanra
Homoiconicity is when the _code_ of a language is represented in a structure
that is primitive to the language. It doesn't have to do with how data is
stored, it has to do with how _the program text itself_ is stored.

The advantage of homoiconicity is that the language itself is manipulable as a
basic type in the language. In Scheme, this means that it's easy to generate,
analyze, and modify Scheme code using simple procedures in Scheme. e.g. I
could (although I wouldn't) generate a _scheme expression_ to compute an
arbitrary fibonacci number with[1]

    
    
        > (define (fib-code n)
            (if (= n 1) 1 `(* ,n ,(fib-code (- n 1)))))
        > (fib-code 4)
        (* 4 (* 3 (* 2 1)))
        > (eval (fib-code 4) (the-environment))
        24
        > (eval (replace '* '+ (fib-code 4)) (the-environment))
        10
    

Notice that I'm not just pushing strings together to write code. I'm actually
manipulating data structures in the language to produce and modify code.
_That_ is homoiconicity.

~~~
Someone
Nice example, but (nitpick warning) that's not a Fibonacci
(<http://oeis.org/A000045>) computation. It computes triangular numbers
(<http://oeis.org/A000217>)

------
fmstephe
I saw Joe speak in London a year or so ago. He was a very good speaker. This
three laws is a very good reflection of his plain spoken and humorous style.
Whether you like Erlang you should take the time to enjoy Joe IMHO :)

------
RHSeeger
> What about Elixir? This gets closures right:

I can't say I agree with his analysis of closures. My understanding is that
closures close around variable scope. If the variable changes (something that
can't happen in a pure functional language) then the closure sees the change.

Elixir closes around the value instead of the variable. While that may be more
convenient/obvious in some places, it removes functionality in others.
Specifically the old adage about closure's being a poor man's object and vice
versa isn't true if the closure doesn't close around the variables themselves.

~~~
jeremyjh
What is the semantic difference when everything is immutable? I'm not sure if
you are right that it closes over the value rather than a reference, and I
can't think of any way to test the idea which suggests to me it is not
meaningful.

~~~
mamcx
Yeah, perhaps in the world of Erlang, have a mutating closure make not sense.

------
drallison
The title makes no sense. The "three laws" are observations about how people
respond to a programming language design. They do not make any sense when
applied to a design or the design process.

~~~
ScottBurson
It certainly was not the article I was hoping for, which would say things
like:

\-- Define and publish a formal syntax for your language. Do not get too
clever with the syntax -- if you can't express some feature cleanly in BNF,
don't do it that way.

\-- Equality must be an equivalence relation: symmetric, reflexive, and
transitive. If you don't know what that means, you have no business designing
a language. [Equality is not transitive in either JavaScript or PHP.]

\-- Comparison operators ('<' etc.) must be transitive. [Violated in PHP.]

\-- Transformations that people expect to work must work. For example, 'if (p)
a else b' must be equivalent in all cases to 'if (!p) b else a' [Visual Basic
violates this].

\-- The scope rules must be clear and straightforward, and not cause
maintainability nightmares. [JavaScript fails.]

------
Aqueous
Those seem like the three laws of everything.

