What are some words or phrases that describe our “cultural ...
How would you describe Swift in three words?
-
Upload
colin-eberhardt -
Category
Technology
-
view
977 -
download
1
description
Transcript of How would you describe Swift in three words?
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 …