Early thoughts on Apple's new Swift language
Yesterday, Apple released its new programming language, Swift. It's a compiled, somewhat C-like language to make writing Cocoa things (OSX, iOS) easier. I've read through the language guide, and it seems mostly sane and reasonable! While I haven't gotten to play with it, here are some of my initial thoughts.
Closures
It has good support for anonymous closures; this is such a powerful feature that it's usually at the top of my list when evaluating a new programming language. The syntax for them is a little peculiar, though:
{ (arg1: type1, arg2: type2, arg3: type3) -> returntype in statement1 statement2 statement3 ... }
The ->
and in
are literal. Fortunately, it turns out that most of those bits are optional; types will be inferred, and you can leave out the entire parameter list and even the return
keyword, turning this:
reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )
into the much less boilerplatey:
reversed = sort(names, { $0 > $1 } )
Great! This is roughly as terse as Perl, which is somewhat unusual for a grumpy compiled language:
@reversed = sort { $a > $b } @names;
Closure sugar syntax
While we're on the subject of closures, Swift also provides some nice sugar syntax for passing them to other functions. Writing this:
some_function(arg1, arg2, { ...closure... })
is the same as writing:
some_function(arg1, arg2) { ...closure... }
This lets you keep track of fewer closing-parens (sorry, Lisp fans) and lets you replicate the syntax of some built-in control structures. If the called function takes no other arguments, the parenthesized parameter list can be omitted, too:
let strings = numbers.map { (var number) -> String in ...logic... return output }
Sadly, this sugar doesn't seem to let you do fancier things like userland-defined try
/catch
/finally
style syntaxes, nor does it seem to provide deferred argument evaluation required to actually duplicate something with a predicate like if
or while
. However, it's there, and it's a good start.
This sugar syntax, combined with the facts that the predicate for an if
isn't wrapped in parens and statement termination is implicit, makes me wonder if you could construct some kind of goofy syntax ambiguity. Take the following code:
if some_function { ...block 1... } { ...block 2... }
If some_function
is a function that doesn't take another function as its last argument, then block 1 becomes the body of the if
, the predicate tests whether some_function
is true, and block 2 is merely a closure in void context. However, if some_function
does take a function as its sole argument, then block 1 becomes a closure being passed to some_function
, the result of the call to some_function
is used as the predicate for the if
, and block 2 becomes the body of the if
! Weird.
Implicit statement termination
So remember back in 1995 when JavaScript decided it was going to have automatic semicolon insertion and everyone eventually realized that wasn't a good idea and everyone always used semicolons anyway and JSLint would yell at you if you didn't because otherwise you'd accidentally write ambiguous stuff like this?
function please_dont_tell_douglas_crockford(a, b) { return { apples: a, bananas: b }; }
Well, Swift took a page from JavaScript's book, but it took the wrong page, and now it has optional semicolons too. See the weird syntax in "Closure sugar syntax" above for one way I hope it doesn't come back to bite them.
Dear langauge designers: please don't make formatting carry semantic meaning. Much like you can't take the implication "it's raining implies it's wet out" and turn it into "it's wet out implies it's raining", so too can you not take "statement ends imply line breaks" and turn it into "line breaks imply statement ends". Semantics and style have no place mucking about together. (I'm looking at you, Python.)
Custom operators
Man, this is a slick feature. These days, you don't usually see languages with features like this that are widely pushed by big companies. In Swift, you can craft entirely new operators so long as they use the approved characters (and since you want to be able to statically parse this thing, that's a fine restriction to impose).
In the documentation example, they create a new +-
operator on Vector2D
s which add the X coords and subtract the Y coords:
operator infix +- { associativity left precedence 140 } func +- (left: Vector2D, right: Vector2D) -> Vector2D { return Vector2D(x: left.x + right.x, y: left.y - right.y) } let firstVector = Vector2D(x: 1.0, y: 2.0) let secondVector = Vector2D(x: 3.0, y: 4.0) let plusMinusVector = firstVector +- secondVector // plusMinusVector is a Vector2D instance with values of (4.0, -2.0)
You declare new operators with the operator
keyword; for infix operators, you also specify the associativity and precedence. Then, you just create a function with the same name as the operator which takes those types. Not bad! The next developer to create an operator named /=-+*%<>!&|^.~
will receieve a code review failure and a public shaming.
Polymorphism
At long last, we've escaped the era of Java and its totalitarian state of single-inheritance class hierarchies. Er, no, wait — the opposite of that.
class SomeClass: SomeSuperclass { // class definition goes here }
Oh well. At least it has interfaces, although it calls them protocols because that's what Objective-C calls them and we can't be smug about our programming language if we use the same words as everyone else to describe it.
Namespace collisions
And finally, "Swift" is already a programming language. Apple even links to it at the bottom of their marketing page and "borrows" their fancy bird icon. Not very nice, Apple.
So, there you have it. Swift isn't terrible! It lives in the Objective-C ecosystem, so expect to see it in Apple OS applications near you.