It made me realise that somewhere in my programming brain I was differentiating between ‘old world’ and ‘new world’ syntactic features, and the more I thought, the more interesting the thought was.
So the reason I am writing here is to try to examine what it was about CoffeeScript that prompted the thought, by presenting some syntactic features that, to me, feel ‘modern’. I’ll also try to explain why I think each feature belongs in a modern language.
1. Stabby Lambdas
The obvious number 1. CoffeeScript’s lambda syntax uses the form
(arguments) -> body. The style is probably derived from
also uses it, and it’s more recently been adopted by
C# and (in a
slightly backwards form)
What this says about language evolution is obvious, I think: programmers want to use anonymous functions. They want to create them quickly and easily, with a meaningful and noise-free syntax. I’d suggest that this is evidence of the current popularity of functional programming style, which is probably a result of the emerging necessity to program for concurrency. I’d also venture that most programmers using this style are interested less in concurrency (at the hardware level) than in a convenient syntax for working with event-driven systems (as well as a language-level Strategy pattern).
2. Noise Reduction
CoffeeScript makes parentheses optional in many cases (as does Ruby);
it also, in certain cases, makes braces for declaring object literals optional; commas
separating object key-value pairs and array elements can be replaced
with newlines; semicolons as line delimiters are not used; comparison and
logical operators can in many cases be replaced with equivalent
English words (
To the same effect, CoffeeScript, like Ruby, offers flexibility in
conditional expressions, so that
unless can be used in place of
not, and any conditional operator can be used postfix, allowing
bon mots like
return unless x is 5.
This makes the language easy to read. It reads fluently, uninterrupted by messy, alienating punctuation. Sometimes this visual clarity is bought at the expense of semantic clarity, though, and the CoffeeScript compiler can bite you if you’re too laissez-faire. Also, how to ‘phrase’ your code becomes an additional, and possibly unwelcome, decision. Rubyists have long faced these issues, and adherence to the language’s idioms is now nearly as important as correct syntax.
The movement to greater flexibility and fewer sigils seems to have met with more approval than hostility, though, and I’d argue that a driving reason for this is that less noisy, more malleable syntax enables the creation of domain-specific languages. Rails famously leverages Ruby’s syntax to create what amounts to a declarative language to describe things like entity relationships; other frameworks have tried to follow suit and been frustrated by their host language’s lack of flexibility. I won’t name names.
3. Expressiveness through Expressions
In CoffeeScript, As in
Ruby, Scala, OCaml, Haskell and Lisp, (almost)
everything is an expression. In simple terms, this means that
every language construct returns a value. An important consequence of
this is implicit returns: because every construct must return a
value, all functions must return a value, whether
return is called
explicitly or not. By default, a function returns the value of the
last evaluated expression. This, again, makes for a very concise and
expressive syntax, which feels like a function just is its evaluated
This applies to conditionals too:
(Note that this is not ‘idiomatic’ CoffeeScript.)
CoffeeScript adds a coalescing existential operator,
?=. This is
particularly useful in combination with the ‘everything is an
expression’ behaviour described above:
It can also be used for simple memoization:
And even to conditionally call a function:
You may have noticed that most of the languages I’ve mentioned above are some distance from ‘modern’; Scala (released 2003) has the best claim. The others range from early adulthood (Ruby, mid-1990s) to spry seniority (Lisp, late 1950s). Why do aspects of their syntaxes, then, seem to contribute to a sense of modernity in language design?
I think this is quite simple: they don’t look, or act, too much like C.
As a result of C’s (and its successors’) popularity, alternative
languages like Lisp and Smalltalk rather faded into the background;
their practical elements were absorbed, but their syntaxes were
repressed. One could argue that Perl brought some of their syntactic
ideas closer to the mainstream – I don’t know enough Perl to have an
opinion. But once you’ve written Ruby or Python or CoffeeScript,
all of them strongly influenced by more humanist languages like the
aforementioned, it’s hard to justify another set of braces, another
for i = 0;. And there you are. Old world:
C. New world: not C.
The above is a small selection of things I want from a ‘modern’ language. Others might be (not in strict order):
- Docstrings. As an Emacs user, I’m a total convert to the idea that a language should facilitate self-documenting programs. Literate CoffeeScript is a welcome move, but I miss being able to describe method parameters and return values in a defined way. The Emacs Lisp compiler complains if you don’t document a function, mentioning the params in order; this should be the norm.
- Comprehensions are a very handy construct. I wish CoffeeScript would introduce object comprehensions, though.
arguments. Python can do it,
Ruby is on board,
and you can
kind of fake it in CoffeeScript,
using destructuring assignment. The king, of course, is Smalltalk,
– effectively polymorphic method signatures enhanced by keyword
arguments. In Smalltalk, the selector
setRed:Green:AndBlue:points to a different method than
setRed:AndGreen:. Ruby 2.0’s syntax strikes a nice balance, allowing arbitrary arguments in addition to keyworded ones.
Again, I’m not arguing what a ‘modern’ language should look like so much as observing my own prejudice; also, I’m well aware that there are horses for courses, and new(ish) languages like Go and Rust are intended for different purposes than Ruby or CoffeeScript.