Swift for JavaScript developers

Let's have a look at Swift from a JavaScript developer's view. I'll take a look at Classes, Callbacks, Events, Truthy / Falsy and Generics and compare the JS implementation to the Swift implementation.

Classes

You're probably familiar with Classes in JavaScript that use the prototype property.

var Person = function(name) {
  this.name = name;
}

Person.prototype.speak = function() {
  return 'Hey there, my name is ' + this.name;
}

var me = new Person('Mirco');
me.speak();
// Hey there, my name is Mirco

In ECMAScript 6 the same code could be rewritten using proper classes.

class Person {

  constructor(name) {
    this.name = name;
  }

  speak() {
    return `Hey there, my name is ${this.name}`;
  }

}

var me = new Person('Mirco');
me.speak();
// Hey there, my name is Mirco

The same code in Swift looks really similar.

class Person {

  var name: String

  init(name: String) {
    self.name = name
  }

  func speak() -> String {
    return "Hey there, my name is \(self.name)"
  }

}

var me = Person(name: "Mirco")
me.speak()
// Hey there, my name is Mirco

So nothing new here. If you're familiar with Object-Oriented Programming you won't have any problems.

Callbacks

Callbacks in Swift are called Closures. Take the following asynchronous code that uses Callbacks.

var log = function(txt, done) {
  setTimeout(function() {
    console.log('callbacks are ' + txt);
    done();
  }, 1000)
}

log('awesome', function() {
  console.log('and done');
});

As you probably know Callbacks are so 1999 so let's have a look at the same example using native JavaScript Promises.

var log = function(txt) {
  return new Promise((resolve) => {
    setTimeout(function() {
      console.log('promises are ' + txt);
      resolve();
    }, 1000)
  })
}

log('the future').then(() => {
  console.log('and done');
});

Now let's marry Callbacks and Promises and we have the Swift code.

func log(txt: String, #resolve: () -> (), #reject: () -> ()) {
  var delta: Int64 = 1 * Int64(NSEC_PER_SEC)
  var time = dispatch_time(DISPATCH_TIME_NOW, delta)

  dispatch_after(time, dispatch_get_main_queue(), {
    println("closures are " + txt)
    resolve()
  });
}

log("not the same as JS closures",
  resolve: {
    println("and done")
  },
  reject: {
    // handle errors
  })

The function parameters don't have to be called resolve and reject. You could also name them success and failure.

Closures are a bit tricky because we also have them in JavaScript. They are kind of similar but not the same. We have to get used to the wording.

Events

JavaScript is all about Events. Button clicks, window scrolling, blurring input fields, etc. They are very easy to implement with jQuery.

$('.btn').click(function() {
  console.log('button clicked');
});

Or with native JavaScript.

var btn = document.getElementById('btn');
btn.addEventListener('click', function() {
  console.log('button clicked');
});

Swift uses the Target-Action mechanism.

// get reference to text field
@IBOutlet var txt : UITextField

// add event listener
txt.addTarget(self, action: Selector("updated"), forControlEvents: UIControlEvents.ValueChanged)

// handle the event
func updated() {
  println("the new value is \(txt.text)")
}

Events and Target-Action are very similar. You have an Object, add an EventListener and write a Function that handles the event.

Truthy and Falsy

Using truthy and falsy values in JavaScript makes your code much simpler and easier to read.

var txt = '';

if (!txt) {
  console.log('we have no text');
}

In the above example we'd actually get 'we have no text' because txt is an empty String and empty Strings are falsy. Compare this with a more verbose example that gives the same result.

var txt = '';

if (txt === '' || txt === undefined || txt === null) {
  console.log('we have no text');
}

Swift uses optional variables that are similar to Truthyness and Falsyness.

var error: NSError?

if let desc = error.description {
    println("oh noes we have an error \(desc)")
}

Again very similar to JavaScript where you can simply check for the existence of a Variable.

Generics

In JavaScript you can write an add function which simply adds two arguments.

function add(a, b) {
  return a+b;
}

add(2, 3);
// 5
add('hello', ' world!');
// hello world!

That doesn't work in Swift since Swift has Types. You have to specify the parameter type when you define your function.

func add(a: Int, b: Int) -> Int {
  return a+b
}

add(2, 3)
// 5
add("hello", " world!")
// Cannot convert the expression's type 'Int' to type 'Int'

You'd have to write another function add which accepts Strings. And another one which uses Floats. And another for Doubles. But that's pretty stupid so Swift uses Generics. With Generics you can write your function only once and call it with different parameter types.

func add<T>(a: T, b: T) {
  println(a + b)
}

add(2, 3)
// 5
add("hello", " world!")
// Could not find an overload for '+' that accepts the supplied arguments

OK, as you can see it is not that easy. We have to tell Swift what Types can be connected (or added) via the + operator. First we have to implement a new protocol. Swift currently has three built-in protocols: Equatable, Comparable and Printable. Let's create another one called Addable.

protocol Addable {
    func +(left: Self, right: Self) -> Self
}

Second we have to teach Swift that the Types String and Int are addable.

extension Int: Addable {}
extension String: Addable {}

And last but not least we have to use our new Protocol in our add function.

func add<T: Addable>(a: T, b: T) -> T {
  return a + b
}

add(2, 3)
// 5
add("hello", " world!")
// hello world!

Generics is probably the hardest feature to wrap your head around. Just play around with them and you'll understand them and their power pretty quickly.

Conclusion

Swift is a game changer for iOS development. It lures a whole new audience into programming apps for Apple. I was a big fan of Hybrid Apps using technologies like AngularJS, Ionic Framework and PhoneGap but now that I've seen the power and simplicity of developing code with Xcode I'm afraid I have to say that Hybrid Apps will have an even harder future competing with Swift.

Google
comments powered by Disqus