Swift continues its rapid advancement with version 2. New optimizations make your app run even faster, and new syntax makes your code more expressive. Learn about powerful new features like error handling, testability, and availability checking. This session will help you write even better apps by moving to Swift 2.
CHRIS LATTNER: Welcome to What's New in Swift.
I'm Chris Lattner.
I'll start off this talk
and my colleague John McCall will take you
through the second half to take you through what's new.
Before we get going, I thought it would be interesting
or helpful to look at what we're trying to do here.
What are the goals and what are the philosophies behind Swift 2?
We had three big things we were going for.
We want the core features and the core behavior
of the language and the tools to be great.
A lot of this is taking a look at the feedback that many
of you have produced in the process of using Swift.
So a lot of what this is is --
I want to thank you for all the feedback you have.
You guys are continuing to shape Swift
through all the great feedback the producers have that use it.
Second up is safety.
Safety is a core value of Swift.
We really want it to be easy to write safe code by default,
and we think that the new availability
in error handling constructs will be a great new way
to do this.
We want your code to be beautiful.
As programmers, we work with code all the time.
This is quite important to us.
We have added new things to Swift making it easier
to write more beautiful and natural code.
Today we'll talk about five new things in Swift.
Before we get diving into what's new in Swift 2,
I think it is important to point
out that Swift 1.2 was also a huge update.
It was released just three months ago.
Because of time limitations, we don't have time
to talk about it much.
But if you're interested and you haven't seen it already,
check out the Swift programming language book
and the Xcode 6 release notes.
Let's dive in and talk about fundamentals.
Fundamentals is about refining the core behavior
of the language and how it works together.
So there are a lot of little things here.
This will feel like a bit of a random walk, but stick with me.
We'll start off with enums.
Enums are one of Swift's best features.
Here I have an enum enumerating some common household pets.
Enums are great because they're simple to define and use.
On the other hand, if you have played with them in a playground
or printed one out, you may have been left wanting for more.
In Swift 2, enums now carry enough reflection information
that you can print them, and they work great.
CHRIS LATTNER: Next, associated values.
Enums are also great because they're the perfect model
for discriminated union, which is great
when you have two values of different types that you want
to store in one thing.
Right? Associated values are very powerful, maybe you went
and tried to write the obvious thing in either type.
This is a perfect way to model this, but when you went
to use it, you got something depressing like this.
Well, this has been very sad, and none of us like this.
Now with Swift 2 it just works.
CHRIS LATTNER: Let's talk about recursion.
Enums in Swift are actually algebraic data types,
and in other languages,
recursive algebraic data types are really powerful.
You can do some really great things.
The problem is in Swift,
the values in an enum are stored inline.
This means if you have a recursive enum,
it has an infinite size, which is hard
for our current devices to hold.
Maybe next year.
There are workarounds for this.
Everybody has seen probably the box-type that you can turn
into a reference, but that breaks pattern matching,
it is ugly and horrible.
With Swift 2, there is a better way.
It didn't quite make it into beta 1,
but coming soon you'll be able
to mark your cases indirect allowing you
to express this naturally, and pattern matching works great.
Let's move on and talk about scoping [applause].
CHRIS LATTNER: So sometimes you have a name that you want
to reuse or maybe a resource that you want
to make sure is released early.
We have introduced a new Do statement allowing you
to introduce an explicit scope.
In this case, we all have to deal with Internet trolls now
and then, but we try to keep them bound
as tightly as possible.
Do is really important when we bring
up error handling later in the talk.
But taking Do as a keyword led to some potential ambiguity.
It's not ambiguity for the compiler;
it's ambiguity as we read code.
You don't always see the bottom of a big, long statement,
and we have a Do While loop.
To make it superclear by just looking at the introducer
for a statement of what it does, we want to make it superclear,
what something does by looking
at the introducer keyword for the statement.
So we have taken the Do While loop and renamed it to Repeat.
You can immediately tell from the top it that it is a loop,
making it really easy [applause].
CHRIS LATTNER: Let's talk about option sets.
Option sets are a lightweight, superefficient way
to represent a set of Booleans.
You may have seen them if you've worked with various Cocoa APIs,
and you use the see the See Like syntax to Or them together.
The basic syntax like this is actually pretty nice.
The problem is, when you get to the other syntaxes you end
up using, it is a bit less nice.
You create an empty-option set with nil --
it doesn't make sense because option sets
and optionals are completely different concepts
and they're conflated together.
You extract them with bitwise operations, which is a pain
and super error-prone, and you can get it wrong easily.
With Swift 2 we have taken the option sets --
this is even worse, because Swift 1.2 had a first-class set
type, and now the combination of all
of this makes option sets seem like an archaic throwback to C,
which they are [laughter].
CHRIS LATTNER: But Swift 2 solves this.
It makes option sets set-like.
That means option sets and sets are now formed
with square brackets.
That means you get empty sets with an empty set
of square brackets, and you get the full set of standard set API
to work with option sets.
It is supereasy and great.
CHRIS LATTNER: Now, it is also nice
because you can define your own option sets
in an easier way now.
Now all you have to do is define your own set type,
or struct type, struct type for your set, and have it conform
to the new option set type protocol, find storage
to hold your bits, and define the elements you want
for your option set.
With just a simple definition,
you now get all the syntax we talked about.
The thing that's supercool about this,
it doesn't require any compiler matching.
This is done automatically
through a new feature called Default Implementations
and Protocols provided by option set type.
We don't have time to talk about Default Implementations
and Protocols in detail here, but we have a session talking
about protocols going into it deeply.
It is great.
Let's talk about functions and methods.
Swift unifies functions and methods together
into a single func declaration.
This is a great thing that pulls two disparate concepts together
in the type system into a beautiful functional core.
This beautiful functional core is a key part of Swift
that immediately falls apart when you try
to call these things because they take different
This has been a huge pain for a lot of people.
If we look at where this came from,
Swift was following the precedent of Objective-C.
C doesn't have argument labels,
argument labels are superimportant for methods
in Objective-C, and Swift followed.
With Swift 2, we fixed this and more.
Now functions and methods have the same declaration syntax,
and they work the same way.
Now when you call a global function,
you provide argument labels by default.
Everything is uniform.
CHRIS LATTNER: So the key thing to know here is
that this affects pure Swift code.
If you declare a global function in Swift,
you get this behavior by default.
Functions imported from C continue to behave
in the same way they always have because argument names
in C functions are not part of API
and are not thought about as API.
But we like Swift code going forward
to include argument labels on functions.
If you look deeper in what's going
on here, there is even more.
Swift functions take parameters,
parameters can have two different names for each value.
So when you declare something with the syntax,
you're actually getting a default behavior.
The two names that a parameter can get are an external name
that the caller sees and the internal name
that the implementation sees.
By default that first argument has no label shown
to the external client of it and has a name you're probably using
when you implement the method.
Likewise, the second and later arguments all default
to being the same inside and outside.
And that's why you see this behavior
of having an argument label for that argument.
The great thing about this model is
that when you understand this, you can customize it.
For example, in this case, it would make sense to have a label
on that first argument so you know what it is.
You can do that simply by duplicating that argument name.
It is simple.
Similarly, if you want to remove something,
you can explicitly set the name of that to the underscore
to say remove this argument label.
In doing so, we have committed one
of the most heinous naming crimes imaginable
by having a Boolean without a label.
Go me! The even better thing, this whole change,
this makes labels much more prominent in the system.
This is great for having APIs that are friendly to use
and means that we can simplify away a ton of complexity.
So now functions and methods work the same,
but we can also get rid of special rules
for the default arguments and there is the weird pound syntax,
nobody remembered what it did, so now that's gone too.
It is much better.
We'll talk about the compiler and talk about the warnings
and the error messages compiled by the compiler.
Here is code that's reasonable code,
maybe you have written something like this before,
where I'm trying to update a point.
If you gave this a Swift 1 compiler,
it would produce something like this.
I don't know about you, but that's not helping much.
Swift 1.2 made this better.
Swift 1.2 made the error message actually tell me
that there is a problem.
Now I see that indeed I cannot assign to this.
Of course, this is not good enough either.
We have continued to invest in the error messages
and warnings produced by the compiler,
and in Swift 2 it says, hey, you can't assign to x
because Self is immutable.
And Xcode will tell you that you can fix this
by marking the method as mutating.
This is a great way I think many people --
it will help many people understand the mutability model
in Swift better and lead to better code everywhere.
CHRIS LATTNER: Of course, this is just one example.
There is a bunch more.
Another example of warnings we have added are
for if you have a variable that can be declared as a constant,
we now produce a warning, say, hey, use Let instead of Are.
The Swift migrator also automatically moves a lot
of code to using Let instead of Are in many cases.
We'll warn if you declare a value, either Let
or Are, but don't use it.
We even have warnings if you use a functional method
and then ignore the result because you probably meant
to use an in-place mutating method instead,
and we can produce warnings for those.
Those are simple examples.
Let's talk about the SDK.
It's a core part of Swift, it's how well it works with Cocoa.
With plain Objective-C APIs,
the Swift compiler has no idea whether pointers can be null
or not and what the element types of collections are.
We have introduced a number of new features
to Objective-C including the ability to express nullability
and the element types of collections in Objective-C.
There is a whole bunch of other features
that make a great experience for Objective-C code in Swift.
The best news about this, is that the framework engineers
at Apple have done a phenomenal job adopting all these modern
Objective-C features, and the Cocoa SDK in general
across all the platforms feels great in Swift
with no work on your part.
However, if you have Objective-C code, maybe you're mixing
and matching with Objective-C code in your project,
or maybe you have an Objective-C framework that you want
to be beautiful and awesome in Swift,
go to some of these sessions later today to learn more
about these features so you can provide a really great
You probably have to watch one of those on video.
Let's talk about unit testing.
Across the entire tools team, testing is superimportant.
Testing is great in Swift until you bring up access control.
The problem is that Swift requires you
to mark symbols Public to be visible to your unit test bundle
so you can test them, leading to tons of stuff being public
that really shouldn't be.
Swift 2 and Xcode 7 has solved this problem.
Now your code is automatically built in a special mode,
meaning that for your tests they can get access to your public
and internal symbols by default.
You have to use the new app to --
CHRIS LATTNER: The even better part of this,
not only is it easy, it is also --
you still get the right behavior for your release builds,
so you get the performance
and the protection benefits of access control.
We have a bunch of talks on testing,
UI Testing in Xcode will be a fantastic talk.
I highly recommend it.
Let's talk about rich comments.
Playgrounds, they're great, and Xcode allows you
to build beautiful Swift playgrounds right
in the editor using a comment syntax, a rich comment syntax.
The syntax is a variant of Markdown, which is a great,
well-known, very popular, loved syntax.
We brought that to documentation comments as well.
This means you can build rich
and pretty beautiful documentation comments,
and it shows up for clients in your API.
So if you're producing a library,
you can do great things here.
Finally, the migrator in Xcode.
As soon as you open the Swift 1 project in Xcode 7,
it will prompt you and say, hey,
I can upgrade this to Swift 2 for you.
It takes you through a couple steps,
you can pick your targets, and then it gives you a dif.
The Swift 2 migrator is actually pretty phenomenal.
It covers the vast majority of the problems and cases
that you will see moving from Swift 1 to Swift 2,
including the error handling model, moving things to methods,
changes to the SDK, a ton of the option set changes,
all of these things are built in the migrator,
and it does a great job.
There is a ton of new stuff in Swift 2, we don't have time
to talk about all of it right now.
If you're interested in more detail,
I recommend taking a look at the Swift programming language book,
there is a new version up.
Also the Xcode 7 release notes talks about a lot
of these changes in more detail.
Let's move on now and talk about pattern matching.
So probably the first place you encounter pattern matches was
with the if-let statement.
It is a great way to take an optional,
conditionally unwrap it, and then bind that result
to a name with safety.
It is a great thing.
There can be too much of a great thing, of course.
One of the things we saw is that there is the "pyramid of doom,"
which is what happens when you get too many if-lets all nestled
together, and suddenly your code is fifteen levels deep
and you can't understand it.
Swift 1.2 solved this problem
by introducing a compound condition into if statements.
Which makes this really natural.
You can check multiple optionals
and Boolean conditions right inline, and it is a lot nicer.
This didn't solve the problem of early exits.
I'll show you some of what might be the most horrible JSON
processing code you can ever imagine.
It will get better over time.
Let's go with this.
Here I'm pulling various fields
out of an untyped JSON dictionary.
So I'm pulling out a name, converting it to string,
produces an optional, if it doesn't match, I bail out.
Likewise, pull the year out, convert it to an In,
if that doesn't match, bail out.
This pattern is very common if you're pulling lots
of values out, it is better to do this bailout approach
than to deeply nest your code.
The problem with this approach is that then you have
to force unwrap the optional values when you're done.
Here I only use them once, but if you have a bunch
of code using them, you're force unwrapping this everywhere.
You can do things to factor this,
so the implicitly unwrapped optional is a great way
to factor force unwraps into a Mecca of unsafety for you.
This is maybe not the right approach either.
This is ugly.
We introduced a new Guard statement.
The way to look at Guard is it does a check and then bales
out if that check doesn't match.
You can do a lot of things in a Guard statement.
Here we're doing our optional check
and we're binding a value to a name.
The way that it works, the way it can work,
is that it guarantees that your Else exits the current scope.
You can do this in one of two ways, either return, throw,
brake, a lot of ways to exit a scope.
You can also call a No Return function like Precondition Fail
or Abort, and that's a good way of stopping.
What this guarantees for the compiler, it knows with safety
and certainty that the names that are bound can be visible
after the code in the fall-through.
If we take this to our example, our example gets nicer
because now we can use Guard, and we have very safe,
concise checks for this as we would expect.
The other nice thing about this, this builds on the rich,
compound conditionals we had with If.
Now you can merge them together and check multiple Boolean
and optional and other cases we'll talk about later right
in line in your Guard statement.
It is pretty nice.
CHRIS LATTNER: Let's talk about the more exciting
and powerful form of pattern matching, switches.
Switches are I think maybe other people's favorite feature
of Swift because you can do so much with pattern matching
in a switch statement.
You check against an optional like here,
you can do class hierarchy checks, you can check
against ranges, there is no end to what you can do in a switch.
They're great when you want to write a lot of cases,
but they're kind of syntactically heavyweight
when you want to check just one case.
They have to be exhaustive,
you have to have a default, it is a pain.
What we have done, we have taken the power of pattern matching
with switch and with case and brought it
to the other control statements in the language.
This example can be written with a new If case, check,
and you can pattern match
and bind variable names right in line.
CHRIS LATTNER: We have gone further.
Another great statement in Swift is the for...in loop.
So it's very common to want to do some amount
of filtering in a for...in loop.
Some languages have gone so far
as to introduce entirely new language constructs
like list comprehensions to model this kind of pattern.
With Swift we have done two things.
We have added the ability
to do a simple Boolean a filter right inline
in your for...in statement.
But you can also do full-on pattern matching right in your
for loop to give you powerful conditions.
CHRIS LATTNER: That's all I have to say
about our quick tour of pattern matching.
We talked about the new Guard statement, which is great
for early exits, talked
about bringing pattern matching pervasively to the language,
and we didn't talk about some of the other improvements
that you can discover as you start to use Swift.
I will hand it over to John, who will tell you
about availability checking.
JOHN MCCALL: Thank you, Chris.
We often roll out new features, you may have heard
of one called Force Touch.
Force Touch is mostly a hardware feature, of course, but it comes
with a number of APIs.
Like this one on NSButton,
letting me change how a button responds to drags over it.
If I want to adopt this in my own app,
that's pretty easy, right?
I have to write some new event handling code
and then I just need to take my button
and set this spring loaded property on it.
The problem is that this may work great on my dev machine,
but when I farm it out to my test hardware,
I'm going to get a crash like this almost certainly.
That's because this is a new API.
It was introduced in X v10.3.
And, like many of you in this situation, you still have a need
to support an older version of the OS.
How would I fix this?
The way I used to fix this is, okay,
I'm getting this error message about the method not existing,
let me check to see if the method exists.
One way -- there are a lot of different idioms
that people have developed for doing this,
this is common idiom, using Responds to Selector.
The problem is that this is a fraught, error-prone pattern.
For example, I actually have to figure out what the selector is,
the mapping from some Swift language feature back
to some Objective-C selector, it is really not the sort of detail
that anybody should need to know.
It is also, you know, not being checked for me by the compiler
because I'm sort of intrinsically escaping the sort
of checking that the compiler provides.
For example, in this case I have actually forgotten
to add this colon, which means
that check will never actually be true.
In Swift 2 we have a better solution.
By default, the compiler is checking to make sure
that you don't use any APIs that are not available
on your minimum deployment target.
JOHN MCCALL: If I do something like this,
I'm always going to get a diagnostic.
What that lets me have is a sort of safe core assumption
that as long as my code --
as long as my project fully compiles, it is at least free
of this sort of trivial deployment [unintelligible].
Now that's not the entirety of the compatibility story,
of course, but this is a great way to help you adopt new APIs.
I do want to use this.
How do I do that?
We added a new #available condition.
In #available, you list out the OS versions you want
to make sure you test for.
And at the end you use this star to make sure
that if there are any new OSs
that you haven't written this code for,
you at least get diagnostics about the availability there.
Here I've used an If statement,
but I could have used the Guard statement
that Chris showed us before.
It is the exact same sort of condition logic
in all of these places.
That's availability checking.
We think this is a great new way for you to be able to adopt
and take advantage of the new features
of new OSs automatically and safely in your projects.
We'll talk more about this in a talk later today.
I really suggest that you come to it.
The next thing I want to talk about is protocol extensions.
Extensions are a really great feature in Swift.
I can take an arbitrary type like Array
and add my own methods to it.
It is not necessarily obvious why this is an important thing,
but a method is a core part, it is how the native APIs
of that type are expressed.
When I'm adding an extension,
I'm really adding new functionality to a type
that feels just as first class, just as core to the API
of the type of anything of the designer
of the type may have already added.
That has a lot of advantages.
Here I've added a Count If method,
that simply calls a closure for every other array and counts
up the number of times that return True.
There is nothing in this method that's actually specific
to array at all.
This ought to work for an arbitrary collection.
Unfortunately, in Swift 1 I couldn't express this
as a method anymore.
To make this generic over an arbitrary collection,
I would have had to write something like this.
As a lot of you have pointed out to us,
this is not exactly optimal.
The first thing is that this is a lot of extra syntax,
there is sort of a blindness about all of the angle brackets
in it, all of the extra crust to just make this generic.
The second thing is it is no longer a method.
Because it is no longer a method, first off,
it doesn't feel like a natural part of using the type.
Second off, it is a lot less discoverable.
It won't show up in any lists of the functionality on array,
and in particular it's not going to show up in the list
of functionality provided by code completion.
Which means that great, you have written this awesome Count
If thing, but nobody using this will realize it exists unless
you point it out to them.
Let's go back.
We had this extension on array just to add the method to array.
Why can't we just extend -- I don't know --
everything that implements collection type?
In Swift 2, I'm happy to say that now you can.
You extend collection type rather than extending array.
When you do this,
you're automatically adding the method everywhere
to every single type that implements collection type,
not just from the standard library or anything but even
in your own types that happen to conform to this.
Not only is that great for writing your own generic code,
but we found it really lets us overhaul a lot of things
that we weren't really happy with about
with the standard library in Swift 1.
There were a lot of things in Swift 1 that had
to be global functions because they had to be generic
or because we wrote them generic.
Then worse, in order to make the methods we sort
of special-cased certain types, like array has a lot
of these map and filter methods on it.
Other types like Set may not have.
In Swift 2, this functionality is going to be available,
this sort of filter and map functionality is expressed
with extensions, meaning it is available on every single thing.
It makes it a lot more discoverable,
means using the standard library is more uniform,
and we really think that you'll love it.
JOHN MCCALL: I really haven't even gone into a third
of the complexity in the awesome new power of this feature.
We're going to have a talk dedicated to this,
it is a great talk tomorrow.
I strongly suggest you come to it.
It is about the great new design patterns
that protocols enable in Swift.
The rest of the talk is going to be about error handling.
I don't think anyone really likes thinking
about error handling.
It is always sort of this guilty thing in the back of our minds
if you're at all like me.
It is really, really important.
When we were looking at what we could do to Swift
that would really make it a more robust,
more expressive language, we said, okay,
the most important thing here is going
to be doing something about error handling.
When we looked at the solutions that were out there,
in other languages, in Cocoa,
we weren't really happy with any of them.
They all have sort of major pitfalls
that we didn't really like.
Some of them, you know,
are based around propagating the errors around automatically
like with NSError in Objective-C,
what that creates is a lot of repetitive error-prone code
where you end up having
to duplicate logic all over the place.
That means it is very easy to get wrong.
More importantly, when you propagate error values
around yourself, the implicit default behavior is
that you're ignoring errors.
That's just never the right default.
You should have to think about errors at least a little bit.
On the other end of the spectrum, there are languages
that propagate errors around implicitly,
like with exception handling.
But we didn't like how any of those worked either.
There is too much that was implicit, it was too easy not
to think of errors again, and you end up with pitfalls
where you just didn't understand what could go wrong
in your program.
You didn't understand how control could flow
from one place to another.
Again, it wasn't a safe, reliable programming model.
There are really three different ways that functions can fail.
One way is that they can simply -- a lot of functions just fail
in one fairly simple, innate, obvious way.
For example, unless you're running a compiler,
you probably don't care why parsing an integer
out of a string failed, this isn't going to be something
that you're getting the juicy details of
and reporting to the user.
Probably you want to handle that directly.
That's already something that when we looked at it,
this is handled extremely well in Swift already,
just with optional results.
We didn't think we needed to do anything here.
We're really happy with how that works already.
On the other end of the spectrum, there are a lot
of things that are logic failures in your program
that are programmer mistakes, assertions,
indexes out of bounds, the vast majority of ways
in which people use NSException, that kind of thing.
For these things, they really actually shouldn't
When you can recover from this kind of thing,
you're just promoting a less stable program overall.
You don't know what state your program is actually
in if you randomly recover from an index out of bounds.
You could even be creating security problems
in your application.
In the middle, there is this large spectrum of APIs
that can fail in a very rich set of ways.
That's really what we wanted to focus on.
The things that you today in Cocoa would use NSError for.
I want to work through an example for you.
This is a preflight method, I have some sort
of operation I want to prefly to make sure it works.
This is something that a lot of you have written I think before.
I'll check to see whether some file is actually reachable,
and then I'm going to reset some state associated
with the operation.
Now checking whether the resource is reachable,
this is an operation that can fail.
It can fail in a wide variety of ways.
It should report something back because, hey,
somebody calling this really may want
to know why something isn't reachable
and maybe treat it differently depending on why.
If I wanted to use NSError for this, this is kind
of what the code ends up looking like.
I'm taking this error, I'm propagating it out to my caller.
There are things to like about this.
There are a lot of things we don't really like.
It adds a lot of boilerplate to my logic.
I had a tight little two-line function, now it is turned
into this -- you know, it has this If statement,
extra nesting, the extra parameter,
there is a lot here whose sole purpose is
to express there is an error,
and we're propagating it out to the caller.
Worse, again, there is a convention here,
that's a convention you need to know about.
And it's a convention you have to implement manually,
and the compiler's not really going to help you with it.
Again, I made a mistake here.
The convention is that an error happens when you return False,
I'm actually checking it the wrong way.
I don't know why they trust me to even work
with compilers [laughter].
I need to add this Not here in order
to get the behavior I want.
Okay. That's -- well, no, sorry.
Those are the downsides of this.
There is actually a lot that we like about it too.
The first thing is, it is obvious from reading this code
that check resource is reachable is something that can fail.
It says right there in the name, it talks about errors,
it has the explicit error handling thing,
this explicit error parameter.
Similarly, it is obvious
that preflight is an operation that can fail.
Again, explicit error parameter, the return value, et cetera.
The third thing is, there isn't implicit control flow.
I can just look at this thing and understand
where all the jumps in it are.
I can analyze my code statically as a human, not as a compiler.
As a human, I can look at this code and reason
about what it is doing without needing
to know every last detail
of every single function that I'm calling.
Now let's go back to the example.
This is how it looked before.
What's going to happen if I try to compile this in Swift?
I'm going to get an error message
because I'm not handling the error.
There are two components to handling errors in Swift.
The first is that whenever you're calling an API
that can fail, you have to use this Try keyword.
The Try communicates, it is really there primarily
for someone reading the code.
It communicates to you, hey, this is something that can fail.
That means when you're coming back,
when you're maintaining this in the future,
I know straight off --
Reset State, that's not necessarily going
to be called every single time to this function.
That may be a really important thing for me to know.
When I'm writing this code in the first place, it is something
for me to think about.
Hey, should Reset State be called every single time I exit
For a preflight operation?
Maybe. That alone isn't enough,
I'm not actually handling the error in any way.
This is because in Swift, by default, functions can't throw.
That's actually a really core aspect of our design
because what it means is errors are bounded.
You don't have to think about literally everything being able
to throw an exception like it can in Java or C#
or basically every language using exceptions.
Instead, it is really just very specific things
that you know you need to worry about whether they can throw.
And when you call them in your code,
it is always marked with Try.
That combination communicates a lot.
Okay. Well, suppose I do want
to just propagate the error out to my caller.
In order to do that, all I have to do is tell the compiler, hey,
it is okay for this thing to throw the error out.
I do that with throws.
That may not be how I want to handle this.
This is a preflight operation.
I probably want to just swallow the error
and tell whoever is calling me whether
or not the preflight succeeded.
To do that, I have to handle it.
I handle it by writing this Do Catch.
Any code that's within the Do, any error arising within it,
is forwarded, sort of filtered through all of the catches.
So what comes after a catch, well,
anything that you could write in a switch.
The entire power of Swift's pattern matching syntax is
available in a catch.
As a very simple, common syntactic refinement,
catches alone like this is a shorthand for catching it
and binding this special error variable to it.
I could also write a much more elaborate thing.
For example, I may want to treat certain kinds of error
as special, maybe they're acceptable in my preflight.
I don't know why the file not existing would be okay,
maybe I really want to check if it exists and, you know,
isn't actually usable for some permissions reason.
If I wanted to, I can pattern match against the error code
and domain directly like this.
As an aside, there is a third way of "handling errors."
It does often happen that you set up preconditions
such that you know that a particular call to something
that can formally throw can't actually throw.
For example, maybe this file is actually in my app bundle
and I know that if I can't read a file in my own app bundle,
something is really, really wrong.
There's probably no real way to recover from this.
So with this common pattern,
where you really want a fatal error
because an error is thrown,
it has a very compact syntax associated with it, this Try!
All that really does is creates an assertion that the code
within the Try doesn't actually throw.
If it does, your program will crash just
like any sort of assertion failure.
That's something that you can debug very, very easily.
It is not something you want to use all the time,
but when you need it, it is really, really handy.
Going back a bit.
I caught an error.
What kind of thing is an error?
Well, we have a protocol built
in to the standard library called ErrorType.
You can throw any value whose type conforms to the ErrorType.
When you catch something,
that thing that you're pattern matching
against is an arbitrary value of ErrorType.
We think it is actually really important
that we don't track errors more precisely than just whether
or not an error was thrown.
It is not like Java, where you end up with a pedantic list
of every single exception that might have been thrown out
and then you end up with this really complicated propagation
problem every time you change errors.
Just tracking whether an error can be thrown is usually good
enough, almost always.
We think this is a great model.
You can make your own types conform to ErrorType.
This is a process that's a lot easier
to do than it was in Cocoa.
Enums are a great way of expressing this.
They're a great way to express a group of related problems,
just like they're -- you know, so that's especially true
because you can associate data with each case in an enum.
If I want to report a richer error message
with maybe something about the --
maybe I'm checking for some invalid state and I want
to remember what the invalid state was,
I can embed that directly in my enum as an associated value
for that particular case.
All you need to do in order to make an enum usable
as an error is make it conform to ErrorType.
The compiler automatically handles the details
of the synthesis.
This is much better than the process
of creating a new NSError domain and associating things with it.
We think that this will really help you make great,
expressive error-throwing APIs
in your own code when you need to.
Let's go back to that example that Chris had
up before, this JSON processor.
Here I'm returning an error back using an Either type
in the string.
Let's make this look more like it would in Swift.
The first thing is, instead of the string,
I'll use that data error enum I just talked about.
I just have to throw, use the new throw statement in order
to throw those values, and that just works.
The other side of this, of course, is I'll need
to change the return type.
I'm no longer returning an Either type.
This isn't something that every single caller has
to carefully micromanage the return value
of in order to check for errors.
I just change it so that it returns Person
and is also a throwing method, then I don't have to mess
around with these little details.
Let's make a new example that culls
that method we just created.
We parsed out, we have a snippet of JSON, we parsed out a person.
Now we'll use that to parse out an entire sales record involving
that person and some item.
Sometimes it happens that you need to, you know, this is a bit
of a contrived example.
Sorry. Sometimes I want to observe this kind of process.
I'm going to have some sort of delegate, I'll let it know
that I have started reading a sales record.
I have now told it I started reading,
obviously I should tell it when I'm finished reading.
I can add that code down here.
The problem is I'm not doing anything right
with error handling.
It is really easy for all of these -- like --
if my delegate actually has Careful and Variants set
up around necessarily getting called every single time --
getting called when the sale finishes.
If my delegate has variance it wants to maintain
about getting called on both ends, I'll mess them
up if I actually fail the process.
This is a sort of problem that comes up a lot
and makes error handling seem so fragile.
Okay. One way I could solve this, of course,
is that I simply add my call to Did End Reading Sale on both
of these throw sites and then, of course,
I'm still not handling this call down to Process Person.
In order to do something there, I have to add this Do Catch.
This is a really, really -- one, this is incredibly verbose.
But it's also really error prone because it is easy for me
to add new code to this, new kinds of processing
that it then immediately will get out of date
if I actually do something.
If I forget to add Did End Reading Sale along
that particular path.
Swift 2 has a much better option.
It is called Defer.
A Defer statement creates an action.
When you execute it, that action is going
to be executed no matter how the current scope is left.
If I return out of it, if I fall out of it, if I throw an error
out of it, no matter how,
I know that that thing is going to be executed.
That means that as someone reading this code,
maintaining this code,
I feel perfectly confident Did End Reading Sale will be
executed no matter what I do to finish reading the sale.
That's a really, really valuable thing to know.
JOHN MCCALL: I want to make a quick note about implementation.
Some of you who are used to exception handling may be aware
that exception handling in many languages is implemented
in a way that's very, very highly biased
against errors actually being thrown.
It is often three, maybe even four orders of magnitude slower
to return out of a function by throwing an error than it is
to simply return out in the normal manner.
Now, that's necessitated by some aspects of the language designs.
It is not really something that we wanted to imitate in Swift.
All you really need to know here is
that the Swift implementation here is far more balanced,
much more like, basically, an If statement in the caller.
That means it is not completely free in order to call something
that can throw an error.
But it means that you don't have to worry
about our error-handling feature being so expensive
that you can't use it in order for the actual reasons
that you need to if you do need to care
about the efficiency of the error path.
Finally, I just want to note, Swift,
the Swift error handling design works beautifully
with Cocoa APIs.
We automatically recognize the most common conventions you see
For example, methods that have an NSError Out parameter
and return Bool automatically become throwing methods
and the Bool return value goes away.
Similarly if it returns an optional result, we recognize
that pattern as the nil indicates an invalid thing,
and it no longer returns an optional result because the nil,
of course, is subsumed within error handling.
JOHN MCCALL: Just with these two very simple rules we found
that the vast, vast majority of APIs in the system import
and automatically work with this new Swift error handling model
seamlessly and beautifully, and we think this is a great new way
to handle errors in Swift.
I really strongly suggest that you check this out.
You probably don't really have much of a choice,
they're all over the place [laughter].
JOHN MCCALL: You know, we really are proud of this design.
We think it is going to greatly improve the robustness
and the expressiveness of writing code
and let you design your own APIs that work just wonderfully.
Let me sum up.
We have been working in Swift 2 really hard to present,
to give you a new language, really flesh
out the core aspects of programming in Swift,
using the tools in Swift, giving you a safer,
more robust environment, and generally making things great.
An invaluable tool to us, this entire time,
has been your feedback.
We really, really appreciate it.
We are listening, I promise.
If you have things to say to us,
of course you can simply use bug reporter,
but you can also email Stefan Lesser, come on the dev forums,
most of us are there all the time.
We're really happy to respond to any question,
hear your feedback about it.
We really, really value you.
Thank you very much [applause].
Have a great WWDC 2015.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.