Quantcast
Channel: Engineering Serendipity » iOS
Viewing all articles
Browse latest Browse all 2

A look at Apple’s new programming language: Swift

0
0

There has been a lot of buzz over Apple’s new programming language, Swift, and many questions as well. Why did Apple need a new language? How is it different from Objective-C? As a developer, should I learn Swift? We’ll dive into these topics in this post.

A Brief History

Swift is the heir to Objective-C, so it’s very difficult to talk about Swift without first talking in detail about Objective-C. Objective-C was created in the early 1980s and descended from both C and the Smalltalk Language.

While most every programmer is familiar with C, Smaltalk is more obscure. It’s an object-oriented language and uses a message-passing style to call methods. (This will come into play later when we discuss Swift syntax.)

During his exile from Apple, Steve Jobs formed a company called NeXT. This company licensed Objective-C in 1988, and they used the language to build an operating system called NextStep. Flash forward to 1996, Apple’s in bit of a rut and they’re looking to update their operating system…Apple acquires NeXT and uses it as the basis of Mac OS X.

Things were fine for a few years and a small amount of developers quietly made Mac desktop applications. In 2007, everything changed when the iPhone was released. Developers were soon able to release third party apps in the App Store which led to an explosion of interest in Objective-C.

What’s wrong with Objective-C?

So what’s the problem? Why can’t we just use Objective-C until the end of time?
In short, Objective-C was never intended to be as popular as it became. It was used for the OS and Mac apps, but there wasn’t a mobile app industry at the time and no one could anticipate what a game changer the iPhone would be.

Objective-C has a somewhat tough barrier to entry because it doesn’t look like a lot of the languages that descended from C like C++, Java or C#. As far as aesthetics go, Objective-C is fairly hideous.

Here’s a sample of Objective-C code:

NSString *myString = [[NSString alloc] initWithFormat:@"I have %@ donuts", donutsNum];

For comparison, this is how you could accomplish the same thing in Java:

String myString = "I have " + donutsNum + "donuts"

Objective-C can be intimidating to programmers who aren’t used to this syntax. Let’s take a look at some of the issues here.

  • We have square brackets all over there place
  • An asterisk before the variable name
  • @ symbols
  • Lots of extra words cluttering up like alloc and initWithFormat
  • What’s with this “NS” and why is that cluttering up the String?

You’ll see this “NS” in many classes in Objective-C: NSArray, NSString, NSDictionary, etc. It’s a nightmare for autocomplete.

Because Objective-C doesn’t have a concept of namespaces, class names have to be unique, so you need to add a prefix like “NS”. If we were to create a custom string in the MeetMe app, it might have a name like MMString.

The prefix “NS” is a relic from when Objective-C and its Foundation framework were built using NextStep. Again, this was created way before anyone could anticipate how popular it would be to code in the language. If they had a crystal ball and saw the future, there’s a good chance the team at NeXT would have made the entire language easier to use.

Over the years, Objective-C has gotten friendlier with more features you’d expect out of a programming language (like blocks and literals), but Apple was looking for a lighter language with less barrier to entry and to clean up some of the relics of the past — Swift is their answer.

Concise

One of the main benefits of Swift is that it is a much more concise language than Objective-C. Gone are:

  • Semicolons ;
  • [Square brackets ]
  • #import statements for classes
  • Alloc/init, lengthy method names

Back to the previous code samples with the strings — here is the same line in Swift, and you can see it has done away with all the weirdness we pointed out in the previous example, looking a lot more like a modern language:

var myString = "I have " + donutsNum + "donuts"

You can also overload the arithmetic operators with your own custom functionality. In Objective-C, there is no overloading; you have to create a new method name if you want to have different types of parameters for the same method. As you may know, autocomplete gets pretty cluttered with all these extra methods.

In Objective-C you need to access properties with the “self” keyword and also call methods on self. In Swift, the self is implied in properties; you can write it out if you want to be explicit, but you can omit self for conciseness. If you call a function without specifying a variable to call it on, the function is implied to call on self so you don’t need to declare that either.

Objective-C:

self.myProperty = 54;
[self performSomeMethod:self.myProperty];

Swift:

myProperty = 54
performSomeMethod(myProperty)

This is an example they used in the Apple Keynote when they first introduced Swift.

if (myDelegate != nil) {
    if ([myDelegate respondsToSelector:
     @selector(scrollViewDidScroll:)]) {
        [myDelegate scrollViewDidScroll:myscrollView];
    }
}

Here, you see some code you’d commonly see in an Objective-C app where you spend a lot of time checking if the delegate is nil and checking if the delegate has a particular method before you call it.

In Swift, they’ve cut down on a lot of typing with Optionals:

myDelegate?.scrollViewDidScroll?(myScrollView)

The use of Optionals is indicated by the question marks. (Optionals will come up later when I discuss safety.)

Another change that results in more concise code is the use of strict types in collections.

Here is a sample method from Objective-C:

- (void)eatDonutFromArray:(NSArray *)donuts {
    NSDonut *donut = [donut firstObject];
    [donut eatDonutMethod];
}

You pass in an array of donuts, but the compiler doesn’t know that the array only contains NSDonuts. We know it because of clues from the method name (and maybe the documentation) but, for all the compiler knows, there could be strings in that donut array.

So, we create a donut variable and cast it as NSDonut to assure the compiler that it’s ok to call eatDonutMethod on it. Is there a better way? Here’s how this same method could be implemented in Swift:

func eatDonutFromArray(donuts: [Donut]!) {
    donuts.firstObject.eatDonutMethod
}

The syntax is a little flipped, but we have the same name of the array — donuts. Instead of a general array type, this has an array strictly of donuts. This allows us to call donut methods on any object in the array without needing to cast it because it has to be a donut; the code won’t compile if you try to send an array of strings to this method.

It’s a great win for more concise code, but this also demonstrates another feature of Swift — its emphasis on safety!

Safety

All variables are statically typed in Swift, meaning you have to declare if a variable is an Int or a String; for example, you can’t just say it’s a variable and call any method you want on it later.

var donutArray:[Donut] = [jellyDonut, powderedDonut]

While Objective-C is also statically typed, it uses the generic id property in collections as we previously discussed. This sometimes leads to errors happening at runtime when a collection ends up having a type that you weren’t expecting. In Swift, because collections are of a particular type, there will be an error before you compile rather than at runtime if you do pass in the wrong type.

Type can also be inferred; as you see in this example, you don’t need to explicitly declare the variable type.

var donutArray = [jellyDonut, powderedDonut]

Here, it is inferred that donutArray is an array of donuts based on the assignment. Under the hood, this is still statically typed; donutArray is an array of Donuts, even though you didn’t have to explicitly type it out like the line above. You get the safety of static typing, but it’s also concise.

In Swift, variables are only able to be changed if you declare them a var. The preferred practice is to declare your variables as constants using the ‘let’ keyword. Not only does it optimize the code and make it faster, it adds safety by throwing you a warning if you try to change the contents.

let donutArray = [jellyDonut, powderedDonut]

Swift really tries to get you to think about how you’re going to use each variable, which we also see with Optionals. Nil or null pointers cause a lot of problems in programming, and different languages have different ways of dealing with it. In a lot of languages, your program will crash if you try to call a method on a null object.

Because Objective-C was inspired by the SmallTalk language, it uses message passing to invoke methods (told you we would come back to that!). A feature of message passing is that you can get away with calling a method on a variable that doesn’t have the method and the compiler won’t complain. In Objective-C, messaging nil returns nil, so no harm, no foul, no crash.

And yet, this isn’t ideal. What if you need the return value from this method and getting back nil will crash your program? You could wrap this in a nil check, or use the respondsToSelector method, and that is what we have to do all the time in Objective-C. Swift is looking for a better way to handle the nil problem.

Enter Optionals. Here’s an example from earlier — let’s say later on you want to clear out the donuts and set the variable to nil:

var donutArray:[Donut] = [jellyDonut, powderedDonut]
donutArray = nil    // Error!!

You cannot do this because then donutArray would no longer be an array of donuts. A var expects a value at all points of its life cycle, from initialization until it is deallocated. How you can accomplish this is by making donutArray an Optional:

var donutArray:[Donut]? = nil

An Optional behaves like how variables in Objective-C behave in that they can be nil at any time. They also do not need to be initialized to a value.

Optionals should be used only when necessary because they work around the safety Swift has created to try to eliminate runtime errors that crop up around surprise nil variables. The preferred order to create variables is:

  1. let constant
  2. var if it needs to change
  3. optional var if it needs to be nil at some point

Optionals are generally meant to be used with a question mark, meaning that there may be an object there or it may be nil. Sometimes you need to guarantee that there’s a value there. The easiest was to use the underlying value of an option (and least safe) is to to force unwrap it by using an exclamation point.

This is a brute force way of saying, “Just trust me, there’s a value there.” This should be avoided unless absolutely necessary because it goes around the safety of optionals and the program will crash if it turns out you were wrong and there’s no object there.

// Force unwrap donutArray
defaults.setObject(donutArray!, forKey: "donutArray")

// Optional binding
if let unwrappedArray = donutArray {
  defaults.setObject(unwrappedArray, forKey: "donutArray")
}

The preferred way to handle this is using a new statement, “if let” (also known as Optional Binding). This creates a new local constant equal to your optional only if there’s a value there. You then safely use the new constant inside the block.

Optional binding is similar to a nil check, so that seems to go against Swift’s push for concise code. I think that, as Swift develops, the syntax for this situation will become more concise. For now, this is the way to safely handle optionals when you need to guarantee they’re non-nil.

Other Safety Features

Swift has eliminated several features that allowed programmers to be a little lazy at the expense of safety. Here are two conditional statements in Objective-C that both do the same thing:

if (boolIsTrue) {
    // do something
}

if (boolIsTrue)
    // do something

If you only have one line inside the body of an if statement, you have the option of omitting the curly braces in Objective-C. The problem is that it’s really easy to think that you’re just going to need one line, then come back to your code sometime later and add more lines not realizing that you also needed to add braces. Those extra lines will not be tested by the conditional statement; they will always execute!

This is an insidious error because the compiler will not complain; it just always executes the extra code. You may not even know there’s a problem until months or years later when unusual things happen. The most infamous recent example of this is Apple’s “goto fail” SSL bug, which happened while using this same shortcut:

if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
     goto fail;
     goto fail;

Apple decided that this convenience was just not worth the risk, so the brace-less conditional checking in Swift is disallowed. Another area Apple made safer while actually letting us be lazier is in switch statements. Here is an example switch statement in Swift:

let direction = "up"

switch (direction) {
case "down":
    println("Going down!")
case "left", "right":
    println("Going sideways!")
case "up":
    println("Going up!")
default:
    println("Going nowhere.")
}

Notice there are no “break” statements anywhere. They are no longer an option in Swift — every case breaks automatically. While this takes away some of the flexibility of being able to fall through to the next case, it eliminates the common problem of forgetting to type “break” after every case and accidentally falling through when you didn’t intend to.

Instead of falling through to additional cases, Swift allows adding several options to the same case (see the “left”, “right” case). And, thankfully, you can now use non-number types inside switch statements such as strings (as you see in the above example), classes, and optionals.

Finally, switch statements must now be exhaustive, which usually means that a default statement is required. In the case of an enum you can usually evaluate all cases; however, there is no way you can evaluate every possible string combination, so use default if you don’t want to get a compiler error!

There are lots of other examples of safety in Swift, too many to go through in this post. The main takeaway is that Swift was designed to be easier to learn, faster to run, and safer to code in than Objective-C. It is evolving and has had some significant changes in its short lifetime. It remains to be seen how quickly Swift will supplant Objective-C, but there seems to be justified enthusiasm for non-Objective-C programmers looking to get into iOS app development.


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images