Swift

Jun 02, 2014 14:46

Today Apple introduced a new language called Swift, along with some pretty hot livecoding environment which, while neat, is an area I'm not very expert in so I'm going to ignore. I am certain the livecoding nerds will discuss it elsewhere.



Swift-the-language I've just finished (quickly and lightly) reading the manual for, so I'll suggest you take my commentary with a grain of salt, but I can point out some things that might be of interest to rushed readers who don't see the obvious bits quite so obviously as someone recently working in this space. Several other Rust nerds are also busy examining and commenting.

Logistics

  • It is LLVM-based and compiles to native code like many recent languages. It will probably run quite fast and target many devices natively, including client-side where memory use and latency kinda still matters.
  • It appears to have "Objective C object model interop" as a hard design constraint, which limits some of the stuff they can safely do.
  • It appears to be proprietary, though I hope for its sake this is not true!
  • It seems to borrow quite extensively from C# and ... I don't know how to say this politely or modestly ... Rust. Which is flattering if true! Of course I'm biased. Also a language pluralist, and since Rust is a major cobbling-together of things we liked in other languages (ML, C++, C#, Lisp, Ruby, etc.) I don't mean this to be claiming any sort of originality. It's nice to see ideas we liked and were trying to promote spreading elsewhere. I'd love to see some posts from the design team talking about their process, what they liked and disliked in other languages, tried to borrow or adapt or reinvent themselves. Convergent evolution happens a lot in languages (often to funny effect).

Features

  • No explicit pointers (but see below re: inout), it relies on the value/reference type dichotomy like C#. This is a half-way step to regaining some of the performance you lose moving to an all-heap system like Java (note: Java is toying with value types now too) without having the cognitive and design load of explicit pointers. This looks like its biggest difference from Rust. It also means that you can't easily (say) take a pointer to the middle of another structure or array. Which is sad, but a reasonable compromise.
  • Obviously in keeping with that, no real mechanisms for reasoning about ownership. When you have a reference type it's an ARC pointer into a shared heap (or its weak partner), period. Regions, uniqueness and all the associated performance and also cognitive load from Rust is not present.
  • Single inheritance classes with explicit overriding and properties, plus multiple inheritance interfaces ("protocols"). This is the norm these days, very C#-ish again, thought the protocols do not appear to have default methods they can carry with them. Classes are reference types, unlike structs which are value types.
  • Protocols get to play double duty as either concrete types (in which case they denote a reference type you can acquire with as from any supporting type) and as type constraints on type parameters in generic code. This is a delightful convenience Rust stumbled into when designing its trait system and I'm glad to see other languages picking it up. I'm sure it has precedent elsewhere.
  • Post-hoc adaptation of types to unrelated protocols using extension. I'm not sure what the coherence rules are on this, I can't find them.
  • Lambdas appear to use a very similar Ruby-ish block form (right down to the trailing argument form!) that Rust used a year or two ago but has now moved away from (I kinda liked it). Also a cute even-shorter form using numbered variables, like the Clojure #() reader macro.
  • Nice normal functional-language-y algebraic types with tuples and sum types, the latter introduced with enum as in Rust. Pattern matching and destructuring binding as you'd expect, nearly identical to Rust except obviously without the wrinkle of trying to bind explicit pointers. Also they avoided all the syntactic ambiguities that wound up in Rust's pattern language, much to my dismay (they get disambiguated during name resolution later).
  • Local type inference, tidied up numeric types, nicer literals, no implicit coercions. Yay.
  • Script-language-y (and Go-ish) support for dictionary literals. Minor, but will be popular.
  • A basic module system without globs, grouped imports or renaming. No visibility control. Re-exporting is supported though, through attributes.
  • No macro system as far as I can tell.
  • Non-pervasive-NULL, thank goodness. Instead, a copy of the option-type / nullable sugar that shows up in C# and the recent Facebook "Hack" language, including quite a bit of sugar for option chaining, forcing and binding. This is great.
  • let and var to differentiate immutable from mutable bindings.

Peculiarities

  • Arrays have strange copy-on-extension semantics, but I think are always in the heap, maybe? Strings are also seemingly CoW and heap. I think. It's unclear.
  • Unclear how or if you're allowed to implement the iterator protocol yourself.
  • Visually confusable .. and ... operators for exclusive and inclusive ranges.
  • Parameters can be inout and such arguments require the seemingly invincible unary& operator! Funny, the inout keyword (also in Objc) refuses to die! In Rust, before we grew a first class region pointer ("lifetime") system, we did this sort of thing also ("parameter modes"). The asymmetry between argument-passing modes and "real" pointers eventually became too much to bear, but I guess Swift is betting it won't be so bad.
  • Seemingly not an expression language. I guess "no macro system" so...
  • No discussion of error handling aside from the algebraic types, option types, and mysterious but occasional reference to "runtime error". Not sure what the isolation / recovery system is, or if there is one. The word "unwind" doesn't occur in the manual.
  • An approach to named parameters that looks suspiciously like the "Olabl" variant of Ocaml. I am not sure how much use this is likely to get!
  • Checked arithmetic by default, and hex floating point literals. Yay!

Overall I mostly agree with Bryan O'Sullivan's tweet:

The academic functional language conferences this year are going to feel like a series of victory laps. Good times, people.
- Bryan O'Sullivan (@bos31337) June 2, 2014

When I started working on Rust, a lot of the motivation was the pain of losing all the nice ML-isms I enjoyed in my hobby hacking when it came time to work in C++ "for pay". We actually tried to pull a lot of this stuff (algebraic types, pattern matching, options, annotation-light typing) into the failed ES4 project as well, but it sank under its weight.

It's remarkable to me that in the years between, we've seen such a shift in what's considered "normal" new-language tech. F# is shipping on several platforms (whether or not M# ever actually surfaces again); Scala is considered an employable skill; C++11 has lambdas and local type inference at least, if not algebraic types or pattern matching; Rust actually exists now; and now one can rely on similar comforts in the Apple ecosystem. How delightful!

This entry was originally posted at http://graydon2.dreamwidth.org/5785.html. Please comment there using OpenID.

tech

Previous post Next post
Up