Since its open sourcing, Swift’s development and evolution has been done completely in the open by both the community and the core team, and has provided us with great insight into upcoming changes & improvements in Swift 3. This includes the reasoning behind the changes with long, in-depth discussions on the Swift mailing lists to back them up. Many of us don’t have the time to follow those as closely as we’d like however, but Daniel Steinberg will get you quickly caught up with everything you need to know about Swift 3 in this talk from App Builders CH. From new keywords and the removal of the C-style for-loop to the new API design guidelines and other commonly debated topics, Daniel covers Swift’s evolution in the past year at lightning speed!
Editor’s Note: To view the official Swift proposal with the considerations of the core team in the Swift Evolution repo, click the corresponding proposal number in each section heading.
What’s New in Swift 3 (0:00)
Swift is now open.
Many people from other communities have said “Does that really mean open?”
Yes it does.
Some of us who have been around since open-sourced Java and other languages remember the fight then. It’s been pretty amazing. The lists have been very open. The discussion’s been in public. The core team has talked about what they’re thinking and why they’re doing things. They’ve taken recommendations from the community and allowed everyone to be involved.
As a result, we already know almost exactly what’s coming in Swift 3.
0025 – Scoped Access Levels (1:19)
So when you ask what can we see about the future, one of the things coming in Swift 3 are different access levels. So at this point, we have 3 access levels:
- public
- internal
- private
The default level is internal
, which means visible within a module. The one that says anybody outside a module can see it is public
. Then there’s private
, which in Swift means something different than it does in other languages. It means visibility within a file.
In Swift 3, we’re going to get another access level and private
is going to be renamed into fileprivate
so that it’s clear that it’s visible only within a file and we’re going to get a fourth accessibility level which is private
, which says even within the file, it’s only visible within a scope.
So for example, in this I have a class. Inside the class I have a private
property and I have a private
method. Those are only visible inside the class even if this is in the same file. So in the past, it would be visible throughout the file; right now, the method that is private
is visible only within the same class. So fileprivate
is what we mean today by private
and we’re getting this new accessibility level which means even more private.
Some people ask for things like protected so that sub-classes see things. We aren’t going to get that, at least in Swift 3. The final list is therefore:
- public
- internal
- fileprivate
- private
0004 – Remove ++ and -- (2:49)
A change that has upset many people is ++
and --
are going away. And there are all sorts of reasons why you think you need them.
For the most part you don’t, but every once and a while there’s a dance you have to do where you have to increment things and so we won’t be able to do this count++
anymore.
while count < upperLimit {
print(myArray[count++])
}
We’ll have to increment things using an explicit count += 1
.
while count < upperLimit {
print(myArray[count])
count += 1
}
Often you’ll have to increment, and then you’ve gotta return, so you’ll have to then subtract one, so sometimes it doesn’t look as pretty as it did.
0007 – Remove C-style for-loops with conditions and incrementers (3:25)
for (int i = 0; i < array.count; i++)
Once ++
went away, it was only a matter of time until C-style for-loops go away. And so, C–style for-loops will not be available in Swift 3; in fact, if you’re running Xcode 7.3, you’ll notice a lot of warnings for these things that are going to be gone once Swift 3 ships.
0053 – Remove explicit use of let
from Function Parameters (3:47)
func double(~~let~~ input: Int) -> Int {
// ...
}
This is interesting. I don’t know if you’ve thought deeply about this, but when you call a method in Swift, what happens is the method makes an immutable copy of the parameters that you pass it. Really what was implied here was this word let
although no one ever wrote that because that was the default behavior. That let is going away.
That’s a recent change in Swift. That came about because of this next one:
0003 – Removing var
from Function Parameters (4:14)
This proposal is removing var
from the parameters and they said once we’re removing var
, shouldn’t we also remove let
? Most of us said we didn’t even know let
existed there.
func double(~~var~~ input: Int) -> Int {
input = input * 2
return input
}
And so for instance, in this method if I take the input and I try to double it and assign it back to the input, remember I’m making an immutable copy and so I can’t change the value of input. To solve this without declaring a new variable we’ve been using var
in the declaration to make that a mutable copy.
It’s still a copy, but it’s mutable so I could change it. This code now runs. That var
is going away and we have to explicitly make a copy here.
func double(input: Int) -> Int {
var localInput = input
localInput = localInput * 2
return localInput
}
Here I’m making a mutable copy that I’ll call localInput
. I assign it back to input
and manipulate the mutable copy. This is one of the cases that a lot of people will do this trick instead:
func double(input: Int) -> Int {
var input = input
input = input * 2
return input
}
Instead of using a different name for the local input, they’ll use the same name and they’ll use sort of a name shadowing. This confuses some people; some people are happy with it. It confuses some people because the two inputs refer to different things. The input on the right side of the equal is the parameter and on the left side is the rest of these.
In this case, it’s probably not too confusing. I think a nicer syntax would be to say var input and not have to assign it back to input and use it the way we used to use var in the parameter.
0031 – Adjusting inout
Declarations for Type Decoration (5:39)
While we’re at it, I said we make it an immutable copy of the parameter. If you want to make a mutable copy, we used var
down below. And if you wanted to actually adjust the thing that you were sending and not make a copy, we have until now used inout
.
func double(input: inout Int) {
input = input * 2
}
inout
is going away from before the parameter name, but it’s not moving far. It’s now decorating the type instead of the variable name. Therefore, it’s just moving over a little bit.
The decision was that it’s really a description of what’s happening here and not of the name, so it’s moved out.
0035 – Limiting inout
capture to @noescape
contexts (6:14)
Another change that’s happening with inout
is that inout
capture is being limited now.
func escape(f: () -> ()) {}
func example(x: inout Int) {
escape { _ = x }
}
Say I have this function called escape()
and escape()
takes a single method as it’s parameter. In example()
, I have this x
which is inout
and I’m going to use that in the function that I passed through escape()
.
So escape()
is going to use this inout x
and at this moment, I’ve got a problem because inout
is expensive. inout
in a way is changing the variable I pass to it, and I don’t know whether example()
is going to go ahead and call this function that I’m passing to it outside of that – outside the scope of example()
itself.
And the way we say “well, I’m only using it within here; don’t worry compiler!” is you label it with @noescape
up there:
// safe because @noescape => closure
// can't be called after function returns
func noEscape(@noescape f: () -> ()) {}
func example(x: inout Int) {
noEscape { _ = x }
}
If it’s labeled @noescape
, then this is okay. The compiler knows that this function I’m passing you isn’t going to use anything you pass it outside of this scope, and so it’s okay to go ahead and do this.
There’s a second way to handle this.
// [x] is a capture list
// a constant is initialized to have the value of x
func escape(f: () -> ()) {}
func example(x: inout Int) {
escape { [x] in _ = x }
}
If my example()
takes this inout x
in my escape()
– now this is not an Array, it looks kind of funny this way. What this is the capture list. You usually see this when you label something as weak
in a capture list or unowned
in a capture list. Here we’re just explicitly saying I want to capture x
and the default capture level is strong
. And so this says “yes, I am using this inout x
, but I’m going to capture it here.” What I’m making is a copy of the thing that’s being passed inout
and so I’m not worried about it.
So these are the two ways we can deal with this inout
inside of a closure.
0049 – Move @noescape and @autoclosure to be type attributes (8:11)
Now there’s a little mistake with what I wrote before with @noescape
and that is that it doesn’t go here anymore.
func noEscape(f: @noescape () -> ()) {}
func noEscape(f: @autoclosure () -> ()) {}
One of the changes coming in Swift 3 is it’s going to move to describe the actual function being passed instead of being out front and that’s also true for @autoclosure
. Isn’t it going to be fun when all our code stops working before migrating?
0002 – Removing currying func declaration syntax (8:35)
Removing currying function declarations syntax worried some people cause they misread this as meaning that Swift was removing currying. They are not removing currying. They’re just removing one of the ways that we’ve written functions with currying.
func curried(x: Int)(y: Int) -> Int {
return {(y: Int) -> Int in
return x * y
}
}
For example, in this curried function, notice it accepts an X and it accepts a Y and it returns an Int
. If we look a little more closely, you see it looks like it has one argument and then it has another argument and so I call it through curried(7)(8)
. That’s a little messy. Not the calling part, but the definition part. The definition part is going to go away because really what’s happening here is I’m currying the seven.
func curried(x: Int) -> (y: Int) -> Int {
return {(y: Int) -> Int in
return x * y
}
}
I’m passing that seven in for the X and really, I’m getting back this function which says I’m going to multiply whatever you pass in as Y times seven. And then when I apply it to the eight, I get seven times the eight.
So I’m doing this in two pieces. I have a curried function where the X is going to be captured. It’s a closure; all functions are closures. Once I’ve captured that, I pass in a Y, the Y will be working with that.
What the Swift core team said is, “Look, instead of being confusing and having these parentheses here, let’s be more explicit and let’s say that what you’re doing when you’re passing the X is you’re returning a function and then you’re applying that function to the next thing.” So that function that you’re returning when you pass in an X is this thing in the curly braces. Currying stays, the syntax changes.
0022 – Referencing the Objective-C selector of a method (10:43)
I want to talk about some of the changes to Objective-C. One of them is we’re changing the way we reference the Objective-C selector of the method. As of Swift 3, we’re going to have to use it with this #selector
. For those of you coming from Objective-C, this should look very familiar. This looks like @selector
that you’ve done before.
#selector(callbackMethod)
#selector(MyClass.callbackMethod)
#selector(MyClass.callbackMethod(with:))
You’ll notice with @selector
, you would have called this callback method colon because it takes a parameter. In this case, there is only one callback method so we can use pound selector here. If we need to further help the system and say well, it’s the callback method that belongs to this class, we can specify that it is the selector for my class dot callback method and if I add a second callback method with a different signature so you have to decide which one you want, in that case, this would be wrong.
We’d have to specify which one we want and we would do that by saying it’s the my classes callback method that takes the parameter with the label width. You can be as specific as you want, but you can also be shorter if you don’t need to specify the class or the parameters.
0033 – Import Objective-C Constants as Swift Types (12:21)
The other changes coming to Objective-C this one I just love. They’ve been pushing you towards this for a while if you think about it. All of those table cell row animations, all of the type of UIButton
s that you can have, the states you can have. If you have a constant that looks like this, Apple’s been pushing you to use the same prefix for all of the constants:
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMassIndex;
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyFatPercentage;
HK_EXTERN NSString * const HKQuantityTypeIdentifierHeight;
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMass;
HK_EXTERN NSString * const HKQuantityTypeIdentifierLeanBodyMass;
Now they said, if you’ve been listening to us and doing what we’ve advised, we can translate that into Swift and this thing will become an enumeration and those will become the cases:
enum HKQuantityTypeIdentifier : String {
case BodyMassIndex
case BodyFatPercentage
case Height
case BodyMass
case LeanBodyMass
}
It will come into Swift as this and that’s been really nice throughout the Apple APIs and that’s going to be one of the changes you’ll see going forward.
How did we know it’s string? If you look at all of these constants that you’re bringing in, they’re all strings. So we knew that the raw value for that must’ve been a string. So this will be our enumeration that we get from those constants. They’re really nice to use.
0005 – Better Translation of Objective-C APIs Into Swift (13:23)
In general, we get better translation of the ObjC APIs into Swift. One example is shortening things and getting rid of some of the redundancy.
// Swift 2.1
let color = NSColor.blueColor()
// Swift 3.0 - prune redundant type names
let color = NSColor.blue()
If I have a color that’s an NSColor that’s a blue color, there’s this redundancy between NSColor
and blueColor
. This is going to be shortened and it will just become blue.
Here are a few more examples that make natural sense:
// Swift 2.1
rootViewController.presentViewController(alert,
animated: true,
completion: nil)
// Swift 3.0
// Nullable trailing closures default = nil
// Animated default = true
// Prune redundant type names
rootViewController.present(alert)
You’re going to see your Swift getting less wordy without leaving any information out. It’s less repetitive, and so you’re not having to repeat the same words over and over.
Next, if I have a property and it’s a bool, one of the changes in Swift 3 is that we’re going to prepend “is” to that and so all of those properties that we’ve taken where we have an Objective-C getter=isSomething
, they’re going to come into Swift as isEmpty
.
// Swift 2.1
addLineToPoint(myPoint) // Calling
func addLineToPoint(_: CGPoint) // Definition
// Swift 3.0 - prune redundant type names
addLine(to: myPoint) // Calling
func addLine(to point: CGPoint) // Definition
Again, redundancy; I’m calling a method add line to point and I’m passing it in a point and so the signature of the method looks something like this. Why do I have to say to point if I’m passing it a point? So, what you’re going to see in Swift 3 is a lot of this. You’re going to see a lot of moving this to point inside and you’ll see that kind of interesting. It’s add line to point; to is the external label. Point is the internal label. So when we call it, we’re saying add line to and we just pass it by point.
I don’t have to tell you it’s a point. The compiler knows, you know, we all know. I’m finding this use just so much more conversational and it takes me back to Objective-C in the way we sort of imagine code talking to each other.
func addLine(to point: CGPoint) // Definition
Notice that in that last example, we added first argument labels. We’ll do a lot of that in Swift and we’ll talk about that in a little bit. In general, we’re adding argument labels where you may not have used them before and we’ll get back to that.
Something that seems to upset people is URLHandler will now come in if it’s a property will now come into Swift as lowercase for imported types.
var URLHandler
// turns into
var urlHandler
Where this upsets me and I just have to get over it is this is also going to be true in enumerations.
enum Currency {
case Dollars
case Euros
case Pounds
case Yen
}
Instead of writing this for an enumeration, we now write this for an enumeration and it just looks wrong.
enum Currency {
case dollars
case euros
case pounds
case yen
}
But it will look right within like four months and we’ll think that’s the way it always should have been.
0036 – Requiring Leading Dot Prefixes for Enum Instance Member Implementations (17:12)
enum Currency {
case dollars
case euros
case pounds
case yen
var symbol: String {
switch self {
case .dollars:
return "$"
default:
return "I don't know"
}
}
}
Inside of enumerations, when were talking about enumerations, we’re using leading dot prefixes and what that means is this: here I am inside of an enumeration and I’m switching on self in case dollars. There are two ways of writing this at this moment and starting in Swift 3, the dot will always be required even inside of. So it’s always been required outside of the enumeration, and starting in Swift 3, using the dot for each case will be required inside. I love changes like that because it’s consistency. It means we know what to expect whenever we encounter code like this. This is kind of a cool thing.
0043 – Declare variables in case
labels with multiple patterns (17:53)
enum MyEnum {
case case1(Int, Float)
case case2(Float, Int)
}
switch value {
case let .case(x, 2), let .case2(2, x):
print(x)
case .case1, .case2:
break
}
Here inside of my enumeration, I have two cases and notice in case one the en comes first and in case two, the Int comes second. So when I switch on the value, I say, “Well, my second in case one is a Float and my first in case two is a Float,” and in either case I want to say “If that float has value two.”
Starting in Swift 3, I can do that all at once. Instead of having these separate case statements that probably had the same body to the case statements, I can bind to the two as the Float in case one where it comes in the second position and case two, where it comes in the first position. And this is something we haven’t been able to do before, and then just use that X whatever it is in the Int position and the nice thing here is we also get the case where the float is not two, so we’re handling all the other cases as it flows through here and then this case we’re just breaking afterwards.
This next one is kind of silly at first, but it’ll grow on you.
0001 – Allow (most) keywords as argument labels (18:53)
// Swift 3 calling with argument label:
calculateRevenue(for sales: numberOfCopies,
in .dollars)
// Swift 3 declaring with argument label:
calculateRevenue(for sales: Int,
in currency: Currency)
Allowing most keywords as argument labels. Like var is coming as an argument label. But here’s one that’s less silly: you see that a lot of use of prepositions as we move to Swift 3, and so we’re calculating revenue for and in. These are keywords and we can now use these as labels.
They actually do make your code a little more readable and so I can calculate the revenues for a number of copies and I can do it in US dollars. So for and in can be used as keywords. We’ll be able to do that with most keywords in the language and use them as labels.
0009 – Require self for accessing instance members (19:32)
In Objective-C, we use self everywhere. Those of you who came from Java, you came from C#, you only use this when you have to. In Swift so far, we only use self when we have to.
struct Friend {
let name: String
let location: String
func nameBadge() {
print("I'm", self.name, "from", self.location)
// REJECTED: self. not required
}
}
In this case, if I have properties name and location, with a name badge I can use name and location. It was clear to all of us name and location refer to those properties cause what else could they refer to? This upsets some people. They would like us to always use self just like we did in Objective-C and I’m happy to report that this was rejected.
0011 – Replace typealias
keyword with associatedtype
for associated type declarations (20:09)
Type alias is kind of interesting. Type alias in Swift is used in two distinct ways:
protocol Prot {
associatedtype Container : SequenceType
}
extension Prot {
typealias Element = Container.Generator.Element
}
It is used to say, “Look, I’m a placeholder. You’ll tell me what container refers to later and I’m used sort of as a #define to say that I’m using Element to be the container’s generator’s element.” What Swift decided was to separate these two cases and in the case there’s a placeholder. You’re going to tell me later what I stand for. We’re going to change it from being type alias to being associated type.
Again, it’s really nice that we had a case where the same word was being used for two very different situations and now we have two different words for those.
0046 – Establish consistent label behavior across all parameters including first labels (20:50)
We’re going to label more consistently across all parameters. If you remember from Swift 1, a function you used all of the labels even the first one. You move that same function inside of a class or something as a method, and all of a sudden you’re not using the first label. And in Swift 2, they unified that to drop the first label in both cases, but init was different. Starting in Swift 3, we will use labels for all of the parameters.
// Swift 3.0
func increase(ourNumber: Int, delta: Int) -> Int {
}
increase(ourNumber: 6, delta: 3)
For example, in this, delta
is used in Swift 2, but ourNumber
wouldn’t show up when we call the function. Starting in Swift 3, ourNumber
will now be required as the first label. All of the parameter labels will be that way.
“But Daniel,” you whine, “sometimes I don’t want to use the first label.” Well, you can still use the underscore to suppress it.
// Swift 3.0
func increase(_ ourNumber: Int, delta: Int) -> Int {
}
increase(6, delta: 3)
0023 – Swift API Design Guidelines (21:41)
Probably the biggest discussion in the Swift evolution list is the API design guidelines for the future of Swift. If you aren’t on this list, it’s a really nice peek into the future and you can look at all the proposals. It gets chatty from time to time; just read the ones you’re interested in.
The discussions of Swift API guidelines and how we name things are there. You’ll see these are captured and if you don’t want to follow the list in this Swift API guidelines, which you can find at Swift.org.
// Name functions and methods according to their side-effects
// Array:
sort()
sorted()
In Swift 3, we’re going back to the Swift 1 naming convention, which is just awesome. The rule for that is we should name functions and methods according to their side effects and so there’s a couple of cases of that.
The first case is if I have these methods that don’t have side effects then, they should read like nouns. For instance, distance()
or successor()
have no side effects.
x.distance(to: y)
i.successor()
If there are side effects, then they should be imperative phrases. If I’m sorting something it should say X, sort yourself; X append Y.
x.sort()
x.append(y)
So these are the ones that change it in place and now the rule that combines these says if I have a non-mutating version of a mutating one, then it should use the “-ed” or “-ing” suffix because that’s completely clear. Again in time, we’ll think it’s natural. Right now, I have to think it through every time I see to see which one it is.
sort()
// vs.
sorted()/sorting()
Of course, you can always Option (⌥) + Click on it and see does it return something or not to see whether it is the mutating or the non-mutating one. There are other suggestions still live for those. It may change, but this is the way it’s currently listed for Swift 3.
In Swift 2, they encourage us to prefer methods to free functions. In Swift 1, you might remember things like map
, filter
, reduce
. These were free functions. You had to pass at the array and how you wanted to change it. Once we got protocol extensions these became methods on SequenceType
actually and so that map
, filter
, reduce
, defined in SequenceType
.
In general, any time you can have a method instead of a free function, that’s what we prefer. There are some exceptions and here’s some exceptions:
min(x, y, z)
If there’s no obvious self like who are you calling min on then it can still be a free function. Like with array.filter
, the array is who you’re calling this on, but I’m taking the minimum of three numbers, min doesn’t belong to anything.
print(x)
sin(x)
If the function is an unconstrained generic like print and then a third case is you know, this is the way it’s always been. We could do this as Math.sin(), but we’ve been calling this sin() forever. Why would we change it? So, if it’s established domain notation, we’ll keep it that way.
Methods can share a base name. Notice we have overloading and Swift which we never had in Objective-C. It’s good when they do analogous things so there’s three different versions of something. Having the same name is great.
However, if you look at the UITableView
APIs, it’s like almost every method is called tableView!
, and the stuff that it does differently is inside there. Hopefully, you only share a base name when you’re doing similar things.
// Choose good parameter names
func move(from startingIndex: Int, to endingIndex: Int)
This seems like something we wouldn’t have to tell people, but we do and so if you have a move()
function, it would be nice to have the starting index and the ending index because then it’s clear what everything refers to. I think this is designed for people coming from Java…
// Take advantage of default values
func hello(name: String = "World")
// Prefer to locate parameters with defaults at the end
init(name: String, hometown: String? = nil)
The other thing which is really handy is take advantage of default values instead of having to write a couple of different versions of hello(), here’s a version that’s going to take the default value world.
Where this is really handy is you can get rid of a lot of the inits. If you have a bunch of things to initialize, instead of having all these different signatures, if you’ve got some optionals and things can be nil, then just default them to be nil. It’s only if you specify this one has a hometown and you specify what the hometown is that it behaves differently.
I found this cleans up code a lot. Instead of having a whole family of inits, you can get by with that pretty nicely.
In general, if you have although it’s not a requirement, but if you have default parameters, it’s nice to locate them at the end. Because they are named parameters, they don’t have to be. So if you have several defaults, in other languages, once you hit the first one that you are specifying, you have to specify all of them from then on. We don’t have to do that in Swift. This isn’t a requirement, but just clean it up a nice recommendation.
External Argument Labels (27:10)
// Definition
func move(from startingIndex: Int, to endingIndex: Int)
// Calling
move(from: here to: there)
We talked about the internal labels, but your external labels also make them nice, make them clean, make them so that the person writing the code understands it when calling the method, not when defining it.
When I say move from here to there, this feels like a nice API to me. Even though the internal name for the first one was starting point and for the second one was ending point. Inside the method I’ll call it that.
Think of it in terms of the API that you’re publishing to someone else and prepositions seem to be really popular in Swift 3. It’s what everybody’s wearing this spring.
There are some exceptions for argument labels. For instance, back to min:
// Omit labels when arguments can't be distinguished
min(number1, number2)
There’s really no difference between the different positions and min. It’s not like I care that number one is first and number two is second. So I wouldn’t include argument labels to distinguish between them. If there’s no difference between the arguments, why give them a label? It doesn’t matter.
// Omit labels in full width inits
Double(someInt)
Double(_ anInt: someInt)
If I’m doing some promotion like you’re creating a Double from an Int, then there’s no reason to say double from int or something like that. In fact, if you look at how it’s defined in the standard library, they suppress that first parameter there. If you’re doing these full width inits, you don’t really need to specify. So you’re seeing, you know, instead of the initWithSomethings
from Objective-C, you’re just seeing them called init.
Sometimes you’re seeing them called init the first label is frame, but if it’s something that’s just a full init like this where you’re taking one number type and converting it to another, we don’t have to specify.
// When the preposition applies to the each parameter
func move(from startingIndex: Int, to endingIndex: Int)
// When the preposition applies to the whole
func moveTo(x: Int, y: Int)
x.removeBoxes(having Length: 12)
Prepositions: In this case, from applies to the first and to applies to the second, but sometimes they apply to both and then we tend to move the preposition outside. Move the preposition out, keep the two labels inside and then finally, in this case, even though having refers to what’s inside, there’s only one, so remove boxes having inside/outside not a big deal.
Whew, you made it! That’s just a quick overview of some of the changes and improvements coming in Swift 3. Thank you.
Q&A (29:33)
Q: Sometimes I feel that omitting self
makes it harder for other devs reading my code to understand it. What’s your opinion on explicit self.property
vs. just property
?
Daniel: My answer is slightly different from Apple’s. Apple’s answer is that there’s nothing preventing you from using self, you are simply not required to. Therefore, your team can use it as much as they want, but other teams can opt not to for readability.
Personally, I think it only gets very confusing when I have a local variable in a method that has the same name as a property. In that case, I would use self.property
to differentiate between the two. Otherwise, I would simply use property
because it’s relatively clear that it comes from the instance variable. It’s partly about clarity, and partly about preference.
Q: What’s your opinion on implicitly unwrapped optionals? When should and shouldn’t they be used?
Daniel: There are some cases in the way UIKit works that require using implicitlt unwrapped symbols such as when using IBOutlets, because upon instantiation those outlets have no values; they get set later in the cycle by the storyboard, but for all intents in your code they exist. This is a good time to use implicit unwrapping because it’s pretty much necessary. I would love to see some lazy way to use those kinds of outlets that get set or made later on, and crash if our connection isn’t made at development time. I would love to see one of you propose this on the Swift Evolution List.
Q: I love the Objective-C runtime and the reflection abilities it provides. These abilities are very restricted in Swift; what are your thoughts on that?
Daniel: This is a big discussion lately in which people want optional methods and protocols like we have in Objective-C. These aren’t ready yet in Swift. One great things about Objective-C is its dynamic nature that allows us to check if objects respond to selectors without knowing them. However, Swift’s type-safety is there to mitigate the need for this from the start, allowing you to be fairly certain at compile time what will work and what won’t, as opposed to checking at runtime.
As such, I don’t want optional methods and protocols to check conformance in Swift, because I think that goes against the idea of type safety. Apple’s come down pretty strongly saying that you should know what an object should be able to do – that’s your contract with it. In contrast, in Objective-C, I can swap anything I want for objects at runtime. As a result, I believe that translating Objective-C straight into Swift will lead us into these issues. Instead of directly translating the Objective-C, we have rethink our architecture and adapt it to the Swift type-safe patterns.
I know Cocoa Touch APIs often depend on this dynamic nature, being written in Objective-C, yet I hope at some point we will get a more Swift-friendly version of those APIs and we won’t have to translate Objective-C to Swift nearly as much.
If we think about it, Objective-C is a lot less dynamic than it used to be, and Apple is pushing us towards the direction of Swift for many years now with things like id
pointers becoming UIButton
s, generics allowing us to specify types more closely, and more.
Q: In the Cocoa APIs, is there talk of automatically changing the venerable delegate pattern to closures?
Daniel: Apple is strongly pushing us in that direction as well for the last four years. Three years ago at WWDC, Apple’s talk of Modern Objective-C encouraged passing closures (blocks in Objective-C) as opposed to using delegates. They want us to provide objects with the behavior we want them to execute as opposed to rely on situational callbacks.
Q: What’s the current status with KVO on Swift 3??
Daniel: Same as it was in Swift 2; no changes happened. If you want key-value observing, you have to subclass NSObject
. It’s not a language feature, but a library that can only be supported by descending from NSObject, which can only be a class, not a struct or enum. With that said, you can do an awful lot with didSet and willSet that might get you the same behavior that you really want with KVO.
Q: What’s the best way to keep up with the Swift Evolution Mailing List without reading everything to find the best ones?
Daniel: Erica Sadun has been very helpful. She’s been summarizing the list regularly saying, “Here’s the new things. Here’s the discussions that are active.” I would say that she’s performing a real big service to the community right now. This is her blog, and if you subscribe to her newsletter on the right sidebar of her site, she’ll be a great source for that.
Editor’s Note: Another great source is Jesse Squires’s Swift Weekly Brief, which summarizes progress on the Swift repos, starter tasks for you to contribute, proposal progress, and mailing list highlights.
Receive news and updates from Realm straight to your inbox