Talks

Rubyist meets Swift

There are a lot of reasons I love Ruby. It makes me a happy programmer. Apple recently released its latest programming language into the wild, Swift. Swift is an object oriented-programming language with a functional personality.

I will give you the whirlwind tour of what I have learned in my dabbling with the language. We will compare constructs in Swift to similar implementations in Ruby and contrast the differences. We’re talking language and syntax here, the good stuff. No need to bring your iOS or Cocoa chops :wink:. Perhaps we have established a trajectory to find happiness developing native applications as well?

Ancient City Ruby 2015

00:27:43.760 Good news, everyone! There are no exceptions in Swift; there are just errors. The program just crashes. You can't recover from this. There may be an exception library or frameworks built into the language in the future; I don't know.
00:28:02.240 But right now, this is all we can do. We have to be very confident with the key that you're fetching out of your dictionary because if you fetch one that doesn't exist, the program execution ends.
00:28:18.720 Here it is; we will go through it piece by piece. It looks kind of crazy, but it’s not that bad. We start by opening or extending the dictionary type to define a fetch method on the dictionary type that fetch method has three parameters: a key, a default value, and a closure we’ll call it the default valuer.
00:28:37.680 You’ll note a couple types here that we haven’t seen before—the key type and the value type. These are actually generic types defined on the dictionary type, representing whatever key type and whatever value type were declared with that particular instance of a dictionary.
00:28:57.760 You also notice that the default value isn't optional, so we don’t have to specify a default value. We want to be able to call the fetch method without a default value.
00:29:16.160 And it allows that, so we declare it as an optional defaulted to nil. You also notice that the default value is forced internal, and this allows us to pass that parameter without an external name, wanting to match the Ruby hash fetch method.
00:29:30.320 Finally, the third parameter is the default valuer; the type of this parameter is a closure with no parameters coming in. The output is a value, so after that closure is evaluated, it must return the same type as the key type in the dictionary.
00:29:50.720 You should also note that it’s an optional closure type, and that’s so we don’t have to specify a closure when we call this method. We don’t have to specify a closure when we call this method, and it is optional to meet that robust type signature of the fetch method.
00:30:07.600 After you call the fetch method, you're going to get a value. You're guaranteed to get a value—some value or the error, of course. But we won’t return an optional; we always get some value from the fetch method call.
00:30:24.560 So, this is the body of the method. It’s actually just two lines. First we attempt to bind all these different optionals, either from the dictionary itself, from the default value passed in, or from the closure being evaluated, and then return that.
00:30:44.000 If it can’t, we raise an error. You’ll notice that we're using the coalescing operator here to sort of chain along those different optionals. The first try is just subscript. We’ll just subscript into the dictionary and try to fetch that key. The subscript operator in Swift returns an optional.
00:31:04.480 That's because a dictionary may not contain the key that we're subscripting, but since we’re using the coalescing operator, that evaluates first, and if it did contain a value, that value would be bound to the constant in this optional binding on the left.
00:31:26.720 If it didn't, evaluation would continue to the right side of the coalescing operator and the default value also an optional, if it’s present, it would be bound to the value on the left constant. If it's not there, execution would continue to the next coalescing operator.
00:31:42.720 Finally, it tries to execute the default value or closure. You’ll notice this weird question mark in the middle; that’s the optional chaining. Since the default value might be nil, it's an optional, and we need to chain the parentheses onto the end of it and call those only if that value is present.
00:32:04.960 If it is present, remember, we talked about optional chaining; it always returns an optional, so we can bind the result of that optional back over to the constant on the left. If any of those in that chain evaluate to some value other than nil, they would be returned by the block following the condition of the if statement.
00:32:24.640 Otherwise, there’s no way to find a default value, so we just error out, and execution ends.
00:32:46.560 As I pointed at all those things, here it is: the entire dictionary fetch method defined in Swift. It's really not that bad! I was intrigued that it was quite simple to define. One thing I did want to note is we could also define this as multiple.
00:33:00.720 Since we have a type system in Swift, we could define multiple fetch methods on the dictionary that all have the signature required instead of using these default values and optionals and stuff as parameters.
00:33:15.360 We could just have one that only has a key that would raise an error if the key is not found, but in this case, I really liked being able to exploit some of the different features of the language and see them in action for our implementation of the fetch method.
00:33:32.320 Here’s how it’s used. We have a dictionary with keys and values. We can fetch a known key, and it’s returned. If we fetch an unknown key, an error occurs; that’s that fatal error. If we fetch an unknown key with a default value, it returns the default that we defined.
00:33:48.480 If we fetch an unknown key with a closure evaluating to that value, it’ll just return the evaluated value from the closure. It’s pretty neat to see how close this is to the same thing in Ruby.
00:34:04.480 Here’s the hash fetch method, and really the only difference is that the hash definition is just slightly different. So that’s it! We made it! Woo!
00:34:20.880 So this is what we learned in Swift today. We learned about values and types, options, and conditions, and functions, parameters, protocols; there’s actually a lot more.
00:34:35.200 Obviously, we didn’t talk about custom types. We briefly saw classes in Swift, and there are different semantics between value types and reference types in Swift. That’s all things that you can learn more about on the Apple website.
00:34:53.239 Definitely check that out! I kind of feel like I'm pushing Apple a little bit, but it’s not my intention. I think Swift is a neat language, and I’ve had a lot of fun playing with Swift as a language. I haven’t done any iOS stuff with it; I’ve just been playing with it outside of their app development ecosystem.
00:35:10.240 Also, again I want to mention, we teach boot camps on this stuff at Big Nerd Ranch. They’re a lot of fun! If you like, we kind of go off in the woods and try to disconnect everyone from the internet to focus on learning for a week.
00:35:30.720 I also blog about this, and my blog is sort of similar to the talk in that it shows Ruby examples and their equivalence in Swift, but they go in a little different direction. So definitely check that out if you’re interested.
00:35:49.680 I also did a talk at a local meetup on Swift; this talk was more about just language stuff—it didn’t compare it to Ruby, just 'Here’s Swift, here’s what you can do.' So if you’re interested in Swift, this may be a good resource to check out.
00:36:06.560 And with that, that’s all I have to say! Thank you so much! I am happy to entertain questions if you all want to ask questions.
00:36:18.320 If you have any questions, I’ll tweet slides and examples and all that stuff if you want to look at them.
00:36:26.480 So, what's up?
00:36:37.440 I noticed that you had to do a forced internal for functions past like the first argument. Does that mean that by default you can only have one internal argument and the rest have to be external?
00:37:00.080 By default, on methods—which the distinction between methods and functions for whatever reason Swift calls functions defined on objects or structs or whatever—methods are functions that belong to some type.
00:37:16.880 The default semantics are that the first parameter is internal and all other parameters are external. You can force all of those to be internal, but they are all external; you have to do it explicitly.
00:37:34.080 The reason I think they did that at least at this point is that it’s very similar to Objective-C; in that, Objective-C the first parameter to a function or method is internal.
00:37:49.360 So you can name your functions like 'do this and that' kind of thing. I personally don’t like it. My opinion right now is that they should internalize all parameters and let you opt into the external thing.
00:38:03.040 Another reason for that is when you define a default value for a parameter, I didn’t go too much into it, but if you define a default value, it will force it to be external unless you force it back to internal.
00:38:20.960 The difference is that in functions, which are blocks of code defined outside of a class or struct or type, functions have all internal parameters by default. Functions actually do have all internal parameters.
00:38:35.760 The example I showed, the second one was an external parameter because it had a default value. It was really bizarre to me that just defining a default value makes it external. For reasons...
00:38:51.760 Does anybody else have questions?
00:39:08.960 Oh yeah, what's up? I'm going to use Ruby motion.
00:39:19.880 From what I've heard about Ruby Motion, I haven’t done much iOS work; I’ve really just been playing with this as a language.
00:39:30.080 What I’ve heard about Ruby Motion is you kind of have to know all the Objective-C stuff to use it very effectively. The thing of course that I'm most drawn to is the idea of Ruby Motion where you can breakpoint your iOS code and execute like a repl inline; that seems really cool.
00:39:45.680 But I haven’t used it personally.