Swift does Perl-style string interpolation from locals:
let apples = 3
let appleSummary = "I have \(apples) apples."
Square brackets are used for both lists and dictionaries. []
means an empty list and [:]
means an empty dictionary.
Not sure I'm a huge fan of if
having to take a boolean (although I understand it's consistent with other decisions). In Python, I like being able to say if items
where items
is a list.
Optional values are intriguing: explicitly declaring something to be nullable.
They've gone with:
for (foo, bar) in baz
meaning baz
is a dictionary, foo
the key and bar
the value.
I guess that's because they don't have lists of tuples and so baz
couldn't be a list of tuples (like the above would be interpreted in Python)
EDIT: I think they do have lists of tuples so I guess they just don't have Python's tuple unpacking.
EDIT 2: Oh wait, they do have tuple unpacking. So how does the above work? Maybe it works one way with dictionaries and another way with lists?
There's a syntax for both an inclusive and exclusive range. 1..5
means 1 thru 4, 1...5
means 1 thru 5.
Lexical scoping. Given how often I now rely on it, I sometimes forget that Python didn't have it for ages.
Interesting syntactic sugar: “A closure passed as the last argument to a function can appear immediately after the parentheses.”
i.e.
foo(...) {...}
instead of
foo(..., {...})
Wait, so the main difference between class
and struct
is that one is pass-by-reference and the other pass-by-value?
Disappointed that Swift didn't borrow from Go in not needing implementations of a protocol/interface to explicitly declare the fact.
Ah, I now understand the if let
thing better.
Optionals evaluate to a boolean so if foo
is a String?
then you can say if foo
to test if foo
is non-nil.
Now if foo
is non-nil, you can say foo!
to get that value (you'll get a runtime error if foo
is nil).
So:
if let bar = foo {
...
}
is syntactic sugar for:
if foo {
let bar = foo!
...
}
An additional nice thing about the if let
syntax is that methods like .toInt()
return optionals (rather than raising an exception) so you can do things like:
if let myInt = someValue.toInt() {
// myInt is someValue converted to an Integer
} else {
// someValue is not convertible to an Integer
}
Something to watch for:
-9 % 4 // equals -1
Looks like \(...)
string interpolation supports any expression.
I like that you can label loop structures and then refer to the label in a break
or continue
.
I actually needed that in Python last night.
I'm not yet convinced of the value of external parameter names. I guess they only make sense if you want to keep Objective-C-like naming of named-args without the weirdness that can result from that in the function body.
EDIT: Ah, I see. It seems external parameter names are required if you want to call the function with explicit names and Swift lets you use a different name for that case than what you want to call it in the function body. There is the #
syntax if the name in the function body is the same as the external parameter.
EDIT 2: In light of this, it seems a little odd that parameters with default values are automatically given external parameters names (without needing to use #
).
Interesting to have inout
parameters when you also support functions with multiple return values.
Is it always possible to write:
function name(inputs) -> output {
body
}
as
name = {
(inputs) -> output in
body
}
?
I like that, in Swift, you don't have a separate operator function (like operator.gt(a, b)
in Python) but instead can just pass in >
where the function is needed.
One thing is clear: Swift has a lot of syntactic sugar.
reversed = sort(names, >)
means
reversed = sort(names, { $0 > $1 } )
which means
reversed = sort(names, { a, b in a > b } )
which means
reversed = sort(names, { a, b in return a > b } )
which means
reversed = sort(names, { (a: String, b: String) -> Bool in return a > b } )
which is the same as:
func backwards(a: String, b: String) -> Bool {
return a > b
}
reversed = sort(names, backwards)
and none of that even makes use of trailing closure syntactic sugar yet!
There's a Firefly reference really early on but then on Page 220 of the Swift book there's a Dr Who reference:
println("Lots of planets have a north")
HHGTTG reference on Page 221. Perhaps I should go back and find others.
Given the overlaps between classes and enumerations, I wonder if the best way to think of enumerations is as classes with a finite, fixed set of instances.
One of the interesting things about the if let
with optionals is you can chain optionals together and handle a nil at any level with a single if
.
The postfix ?
(at least after a type T
) is just syntactic sugar for Optional<T>
which is a enum
of None
and Some(T)
which conforms to the LogicValue
protocol.
UPDATE: but now see https://thoughtstreams.io/jtauber/new-in-swift-beta-5/
Working through an iOS development tutorial, I hit a known issue in the first beta of Xcode 6: "Unwind segue actions declared in Swift classes are not recognized by Interface Builder".
I found this: http://stackoverflow.com/a/24030113/112855
but still haven't got it working.
Building Cocoa apps in Swift is a little like what I remember writing Tk apps in Python was like. The biggest challenge is all the documentation is written for a different language binding.
I wonder if an enum with one value is actually a good way to implement singletons.
I also wonder to what extent enums can be used for algebraic data types.
I just spent a couple of hours debugging my port of Minilight from Python (itself a port) to Swift.
The bug turned out to be that in the Python version I could test for non-None and non-zero at same time; in Swift I need to test separately.
So my Python was:
distance = triangle.get_intersection(...)
if distance and (distance < nearest_distance):
...
Now distance can be None
as well as 0.0
and the above code handles both.
My original Swift port, however, neglected the 0.0
case and only handled the nil
case in the clever type-safe way that if let
supports:
if let distance = triangle.getIntersection(...) {
if distance < nearestDistance {
...
The fix was to make it:
if let distance = triangle.getIntersection(...) {
if distance > 0 && distance < nearestDistance {
...
I wonder if that experience is actually an argument for if clauses only taking explicit booleans (contra what I posted here earlier).