The Curious Case of Swift's Adoption of Smalltalk Keyword Syntax
The Curious Case of Swift's Adoption of Smalltalk Keyword Syntax

I was really surprised to learn that Swift recently adopted Smalltalk keyword syntax:  [Accepted] SE-0279: Multiple Trailing Closures.  That is:  a keyword terminated by a colon, followed by an argument and without
any surrounding braces.

The mind boggles.

A little.

Of course, Swift wouldn't be Swift if this weren't a special case of a special case, specifically
the case of multiple trailing closures, which is a special case of trailing closures,
which are weird and special-casey enough by themselves.  Below is an example:

UIView.animate(withDuration: 0.3) {
  self.view.alpha = 0
} completion: { _ in
  self.view.removeFromSuperview()
}



Note how the arguments to animate() would seem to terminate at the closing parenthesis,
but that's actually not the case.  The curly braces after the closing paren start a closure that is
actually also an argument to the method, a so-called trailing closure.  I have a little bit of 
sympathy for this construct, because closures inside of the parentheses look really, really 
awkward.  (Of course, all params apart from a sole x inside f(x)
look awkward, but let's not quibble.  For now.).

Another thing this enables is methods that reasonably resemble control structures, which I heard
is a really great idea.

The problem is that sometimes you have more than one closure argument, and then just stacking them
up behind what appears to be end of the function/method call gets really, really awkward, and
you can't tell which block is which argument, because the trailing closure doesn't get a keyword.

Well, now it does.  And we now have 4 different method syntaxes in one!
Traditional C/Pascal/C++/Java function call syntax x.f()
The already weird-ish addition of Smalltalk/Objective-C keywords inside the f(x) syntax: f(arg:x)
Original trailing-closure syntax, which is just its own thing, for the first closure
Smalltalk non-brackted keyword syntax for the 2nd and subsequent closures.


That is impressive, in a scary kind of way.


Swift is a crescendo of special cases stopping just short of the general; the result is complexity in the semantics, complexity in the behaviour (i.e. bugs), and complexity in use (i.e. workarounds).



In understand that this proposal was quite controversial, with heated discussion between opponents
and proponents.  I understand and sympathize with both sides.  On the one hand, this is
markedly better than alternatives.  On the other hand it is a special case of a special case that
is difficult to justify as an addition of all that is already there.

Special cases beget special cases beget special cases.

Of course the answer was always there:  Smalltalk keyword syntax is not just the only reasonable
solution in this case, it also solves all the other cases.  It is the general solution.  Here's
how this could look in Objective-Smalltalk (which uses curly braces instead for closures instead
of Smalltalk-80's square brackets):

UIView animate:{ self.view.alpha ← 0. } withDuration:0.3 completion:{ self view removeFromSuperview. }.



No special cases, every argument is labeled, no syntax mush of brackets inside parentheses etc.
And yes, this also handles user-defined control structures, to:do: is just a 
method on NSNumber:

1 to:10 do:{:i | stdout println:"I will not introduce {i} special cases willy nilly.".}.



And since keywords naturally go between their arguments, there is no need for "operators",
as a very different and special syntax form.  You just allow some "binary" keywords to look
a little different, so instead of 2 multiply:3 you can write 2 * 3.
And when you have 2 raisedTo:3 instead of pow(2,3) (with the
signature:  func pow(_ x: Decimal, _ y: Int) -> Decimal), do you
really neeed to go to the trouble of defining an "operator"?



Or Swift's a as b, another special kind of syntax.  How about a as:b?
(Yes I know there are details, but those are ... details.).  And so on and so forth.

But of course, it's too late now. When I chose Smalltalk as the base syntax for the language
that has turned into Objective-Smalltalk, it wasn't just because I just like it or have gotten
used to it via Objective-C.  Smalltalk's syntax is surprisingly flexible and general, 
Smalltalk APIs look a lot like DSLs, without any of the tooling or other overheads.

And that's the frustrating part: this stuff was and is available and well-known. At least
if you bother to look and/or ask.  But instead, we just choose these things willy-nilly
and everybody has to suffer the consequences.

UPDATE:

I guess what I am trying to get at is that if you'd thought things through just a little bit, you 
could have had almost the entire syntax of your language for the cost (complexity,
implementation size and brittleness, cognitive load, etc.) of this one special case of a special case.
And it would have been overall better to boot.
