how would you describe swift in three words?

Post on 28-Nov-2014

977 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

A talk I delivered at iOSDevUK 2014

TRANSCRIPT

Intermediate Swift

@ColinEberhardt ShinobiControls

How would you describe Swift in three words?

JavaBoringSimpleGang of Four

C#ExpressiveFunJava++

JavaScriptRapidSimpleBroken!

Objective-CPowerfulUgly

Swift????

Swift hates nil

Value Types

Reference Types

nill-able references

Objective-C ✓ ✓ ✓Java ✓ ✓ ✓

JavaScript ✓ ✓ ✓C# ✓ ✓ ✓

Swift ✓ ✓ ✗

† Non extensible

nil is a bad thing

RACSignal *signal = [[self.services getFlickrSearchService] flickrImageMetadata:self.photo.identifier];

RACSignal *signal; if (self.services && self.photo && self.photo.identifier) { id<RWTFlickrSearch> searchService = [self.services getFlickrSearchService]; if (searchService) { signal = [searchService flickrImageMetadata:self.photo.identifier]; } }

RACSignal *signal = [[self.services getFlickrSearchService] flickrImageMetadata:self.photo.identifier];

Opt-in with Optionals

var person: String? !!var car: String? = "Porsche"

var car: String? // car is nil car = "Porsche" !// checked if let actuallyACar = car { if actuallyACar.hasPrefix("P") { println("It's a 'P'") } } !// unchecked // fatal error: unexpectedly found nil while // unwrapping an Optional value if car!.hasPrefix("P") { println("It's a 'P'") } !// chaining if let hasPrefix = car?.hasPrefix("P") { if hasPrefix { println("It's a 'P'") } }

Swift likes sugar

var car: String? !!var car: Optional<String> = "Porsche"

enum Optional<T> : Reflectable, NilLiteralConvertible { case None case Some(T) init() var hasValue: Bool { get } ! static func convertFromNilLiteral() -> T? }

// sugar free var car: Optional<String> = "Porsche" !switch car { case .None: println("nothing here") case .Some(let actuallyACar): if actuallyACar.hasPrefix("P") { println("It's a 'P'") } }

// checked if let actuallyACar = car { if actuallyACar.hasPrefix("P") { println("It's a 'P'") } }

Opt-out of unwrapping with implicit optionals

var car: String! = "Porsche" !// unchecked - minus the unwrapping if car.hasPrefix("P") { println("It's a 'P'") }

Swift meets Objective-C

Objective-C permits nil

… as a result anything returned by the APIs could be a nil reference

AnyObject!

Variables are always surprised! or confused?

Swift initialisation is strict

Swift initialisation is really strict

The Commandments

Thou shalt initialise all properties of your type!Thou shalt not call super init before properties are initialised!

Thou shalt not call class methods until all properties are initialised!Thou shalt not use super properties before super.init!

Thou shalt only call designated initialisers on the superclass!Thou shalt not call super initialisers from convenience initialisers!

Thou shalt not call class methods before super.init !Thou shalt not kill

Thou shalt initialise all properties of your type!Thou shalt not call super init before properties are initialised!

Thou shalt not call class methods until all properties are initialised!Thou shalt not use super properties before super.init!

Thou shalt only call designated initialisers on the superclass!Thou shalt not call super initialisers from convenience initialisers!

Thou shalt not call class methods before super.init !Thou shalt not kill

Thou shalt initialise all properties of your type!Thou shalt not call super init before properties are initialised!

Thou shalt not call class methods until all properties are initialised!Thou shalt not use super properties before super.init!

Thou shalt only call designated initialisers on the superclass!Thou shalt not call super initialisers from convenience initialisers!

Thou shalt not call class methods before super.init !Thou shalt not kill

Thou shalt initialise all properties of your type!Thou shalt not call super init before properties are initialised!

Thou shalt not call class methods until all properties are initialised!Thou shalt not use super properties before super.init!

Thou shalt only call designated initialisers on the superclass!Thou shalt not call super initialisers from convenience initialisers!

Thou shalt not call class methods before super.init !Thou shalt not kill

Thou shalt initialise all properties of your type!Thou shalt not call super init before properties are initialised!

Thou shalt not call class methods until all properties are initialised!Thou shalt not use super properties before super.init!

Thou shalt only call designated initialisers on the superclass!Thou shalt not call super initialisers from convenience initialisers!

Thou shalt not call class methods before super.init !Thou shalt not kill

Thou shalt initialise all properties of your type!Thou shalt not call super init before properties are initialised!

Thou shalt not call class methods until all properties are initialised!Thou shalt not use super properties before super.init!

Thou shalt only call designated initialisers on the superclass!Thou shalt not call super initialisers from convenience initialisers!

Thou shalt not call class methods before super.init !Thou shalt not kill

Thou shalt initialise all properties of your type!Thou shalt not call super init before properties are initialised!

Thou shalt not call class methods until all properties are initialised!Thou shalt not use super properties before super.init!

Thou shalt only call designated initialisers on the superclass!Thou shalt not call super initialisers from convenience initialisers!

Thou shalt not call class methods before super.init !Thou shalt not kill

Thou shalt initialise all properties of your type!Thou shalt not call super init before properties are initialised!

Thou shalt not call class methods until all properties are initialised!Thou shalt not use super properties before super.init!

Thou shalt only call designated initialisers on the superclass!Thou shalt not call super initialisers from convenience initialisers!

Thou shalt not call class methods before super.init !Thou shalt not kill

class Cat: Animal { ... init(name: String, isLongHaired: Bool) { // initialize *all* class properties // no calls to 'self' methods here super.init(name: name) // perform initialisation that requires self & super // possibly update superclass properties } convenience init() { // can only call designated initializers on self self.init(name: "kitty", isLongHaired: false) } }

Strictness bites

import Foundation !class Animal { let name: String init(name: String) { self.name = name.capitalizedString } } !class Cat: Animal { let catName: String override init(name: String) { super.init(name: name) ! // error: property 'self.catName' not // initialized at super.init call self.catName = self.name + "-kins" } }

Solution - make catName surprised!

class Cat: Animal { let catName: String! override init(name: String) { super.init(name: name) self.catName = self.name + "-kins" } }

Spot the semicolon!

Swift is a bit muddled up!

!class Cat { ... init(name: String) { ... } func updateWithName(name: String, isLongHaired: Bool) { ... } } !func updateTheCatsName(cat: Cat, newName: String, isLongHaired: Bool) { ... } !!// initializers - named parameters let cat = Cat(name: "molly") !// global functions - no named parameters updateTheCatsName(cat, "frank", true) !// methods - second and subsequent parameters are named cat.updateWithName("frank", isLongHaired: true); !

!class Cat { ... init(_ name: String) { ... } func updateWithName(#name: String, isLongHaired: Bool) { ... } } !func updateTheCatsName(meow cat: Cat, newName: String, isLongHaired: Bool) { ... } !!// initializers let cat = Cat("molly") !// global functions updateTheCatsName(meow: cat, "frank", true) !// methods cat.updateWithName(name: "frank", isLongHaired: true)

Delegation patternclass ViewController: UIViewController, UITableViewDelegate { ! ... ! func tableView(tableView: UITableView!, didDeselectRowAtIndexPath indexPath: NSIndexPath!) { } func tableView(tableView: UITableView!, didEndDisplayingFooterView view: UIView!, forSection section: Int) { } ! func tableView(tableView: UITableView!, canPerformAction action: Selector, forRowAtIndexPath indexPath: NSIndexPath!, withSender sender: AnyObject!) -> Bool { } }

Method naming

tableView:canPerformAction:forRowAtIndexPath:withSender:

tableView(_:canPerformAction:forRowAtIndexPath:withSender:)

Swift likes immutability!

Immutability - C#

const

readonly

ReadOnlyCollection

ArrayList

Immutability - Objective-C

const

#define

NSArray

NSMutableArray

Immutability is a first-class concept in Swift

var is a variable, it can be re-assigned

let is a constant, it cannot be re-assigned

Constants are everywhere

for i in 0...5 { // error i = 27 } !!!func square(number: Double) { // error number = number * number }

Mutability in practice

A variable class

class Coordinate { var x: Int = 0, y: Int = 0 } !var coord = Coordinate() coord.x = 56 !coord = Coordinate() coord.y = 57;

Class variable, you can change properties and re-assign

A constant class (almost)

class Coordinate { var x: Int = 0, y: Int = 0 } !let coord = Coordinate() coord.x = 56 !// fails here coord = Coordinate() coord.y = 57

A constant class can be mutated

A constant class cannot be re-assigned

A variable struct

struct Coordinate { var x: Int = 0, y: Int = 0 } !var coord = Coordinate() coord.x = 56 !coord = Coordinate() coord.y = 57

Variable struct, you can change properties and re-assign

Just like variable classes!

Constant structs are immutable :-)

struct Coordinate { var x: Int = 0, y: Int = 0 } !let coord = Coordinate() // error: fails here coord.x = 56 !coord = Coordinate() coord.y = 57 !

Constant struct, you cannot mutate it!

This is super-awesome, by changing a keyword, you change the mutability of the entire object.

Strings, Arrays and Dictionaries are structs

// a variable array var coord = [1,2,3,4] !// can be mutated! coord[1] = 5 // “[1, 4, 3, 4]”

// a constant array let coord = [1,2,3,4] !// error: ’@lvalue $T5' is not identical to 'Int' coord[1] = 5;

Creating Immutable Types

struct Coordinate { var x = 0, y = 0 func transpose() { let temp = x // error: cannot assign to ‘x’ in ‘self’ x = y y = temp } }

Mutating Functions

struct Coordinate { var x = 0, y = 0 mutating func transpose() { let temp = x // no error! x = y y = temp } }

Mutating Functions

// a variable coordinate var coord = Coordinate() coord.transpose() !!!// a constant coordinate let constCoord = Coordinate() !// error: immutable value of type ‘Coordinate' // only has mutating members named 'transpose' constCoord.transpose()

Structs are value-types

func trimArrayToLength<T>(array: [T], length: Int) { while array.count > length { // error: immutable value of type '[T]' only // has mutating members named 'removeLast' array.removeLast() } }

Structs are value-types

func trimArrayToLength<T>(inout array: [T], length: Int) { while array.count > length { array.removeLast() } } !var myArray = [1,3,5,3,8,9] trimArrayToLength(&myArray, 3) println(myArray) // [1,3,5]

Whenever you start typing var, type let instead, only changing it back to var if it does not compile!

Swift is Functional

First-class functionsimport Foundation !func square(number: Double) -> Double { return number * number } !let a = 3.0, b = 4.0 let c = sqrt(square(a) + square(b)) println(c) // 5.0

import Foundation !func square(number: Double) -> Double { return number * number } !let operation = square !let a = 3.0, b = 4.0 let c = sqrt(operation(a) + operation(b)) println(c) // 5.0

Function types

let operation = square

The type of operation is being inferred

But what *is* the type?

Function types

let operation:(Double) -> Double = square

Functions can be:

Assigned to variables or constants

Passed to / from other functions

Fun with functionsfunc * (fn: () -> (), times: Int) { for _ in 0..<times { fn() } } !{ println("Swift rocks!") } * 3 !// Swift rocks! // Swift rocks! // Swift rocks!

http://ijoshsmith.com/2014/07/05/custom-threading-operator-in-swift/

More functional fun …

// non functional var evens = [Int]() for i in 1...10 { if i % 2 == 0 { evens += [i] } } !var evenSum = 0 for i in evens { evenSum += i }

// functional evenSum = Array(1...10) .filter { (number) in number % 2 == 0 } .reduce(0) { (total, number) in total + number }

the sum of all even numbers between 1 and 10

Partial applicationfunc createSplitter(separator:String) -> (String -> [String]) { func split(source:String) -> [String] { return source.componentsSeparatedByString(separator) } return split }

let data = "5,7;3,4;55,6" let commaSplitter = createSplitter(",") commaSplitter(data) !let semiColonSplitter = createSplitter(";") semiColonSplitter(data)

Curried functions

func createSplitter(separator:String)(source:String) -> [String] { return source.componentsSeparatedByString(separator) }

func createSplitter(separator:String) -> (String -> [String]) { func split(source:String) -> [String] { return source.componentsSeparatedByString(separator) } return split }

class Person { let name: String; init(name: String) { self.name = name } func greeting() { println("Hello \(name)") } } !let speaker = Person(name: "Colin") speaker.greeting() // "Hello Colin" !let speakFunction = speaker.greeting speakFunction() // "Hello Colin" !let curriedFunc = Person.greeting curriedFunc(speaker)() // "Hello Colin"

Swift is concise

Sorting an array

let animals = ["fish", "cat" , "chicken", "dog"] !func isBefore(one: String, two:String) -> Bool { return one < two } !let sortedStrings = animals.sorted(isBefore) !println(sortedStrings) // [cat, chicken, dog, fish] !!

Closure expressions as anonymous functions

let sorted = animals.sorted({ (one: String, two: String) -> Bool in return one > two })

let sorted = animals.sorted({ (one: String, two: String) -> Bool in return one > two })

46 characters

let sorted = animals.sorted({ (one, two) -> Bool in return one > two })

32 characters

let sorted = animals.sorted({ (one, two) in return one > two })

26 characters

let sorted = animals.sorted({ one, two in return one > two })

24 characters

let sorted = animals.sorted({ one, two in one > two })

19 characters

50% smaller

let sorted = animals.sorted({ one, two in one > two })

let sorted = animals.sorted({ (one: String, two: String) -> Bool in return one > two })

let sorted = animals.sorted({ $0 > $1 })

7 characters

let sorted = animals.sorted() { $0 > $1 }

7 characters

let sorted = animals.sorted { $0 > $1 }

7 characters

let sorted = animals.sorted(>)

1 character!

Swift is clear

Swift still uses ARC

Swift still has retain cycles

Objective-C syntax

__weak typeof(self)weakSelf = self; [self.context performBlock:^{ __strong typeof(weakSelf)strongSelf = weakSelf; // do something with strongSelf }];

Swift syntax

closure = { [unowned self] () -> () in // do something with self }

Swift is ‘open’

for-in and sequenceclass Fibonacci: SequenceType { func generate() -> GeneratorOf<Int> { var current = 0, next = 1 return GeneratorOf<Int> { var ret = current current = next next = next + ret return ret } } } !for num in Fibonacci() { println(num) // 0, 1, 1, 2, 3, 5, 8, 13 } !

http://www.scottlogic.com/blog/2014/06/26/swift-sequences.html

Literal conversionclass Person: StringLiteralConvertible { let name: String required init(name: String) { self.name = name } class func convertFromStringLiteral(value: StringLiteralType) -> Self { return self(name: value) } class func convertFromExtendedGraphemeClusterLiteral(value: String) -> Self { return self(name: value) } } !var people: [Person] = ["Bob", "Frank", "Brian"]

How would you describe Swift in three words?

Safe

Swift hates nil Swift initialisation is really strict Swift likes immutable types

Muddled

Swift parameter naming is muddled up Swift variables are often dazed! or confused?

Modern

Swift is functional

Swift likes sugar

Swift is clear and concise

SwiftSafeMuddledModern

Swift wish-list

Some form of reflection

Exceptions (try / catch / throw)

A re-write of Foundation, UIKit, CoreData …

top related