generics and inference

34
<Generics: Inference>

Upload: richard-fox

Post on 13-Jan-2017

43 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Generics and Inference

<Generics: Inference>

Page 2: Generics and Inference

<Generics: Inference>→ Rich Fox @RGfox→ I work at Propeller→ I am a contributer to

Page 3: Generics and Inference

Generics and the Art of Inferences→ What are generics

→ What is inference

→ Goal of Talk

Page 4: Generics and Inference

Ex 1. Casting Number Types

Page 5: Generics and Inference

protocol NumberConvertible { init(_ value: Int) init(_ value: Float) init(_ value: Double)}

extension Double: NumberConvertible {}extension Float: NumberConvertible {}extension Int: NumberConvertible {}

Int,Float,Double: NumberConvertible

Page 6: Generics and Inference

extension NumberConvertible { func convert<T: NumberConvertible>() -> T {

switch self {

case let x as Float: return T(x)

case let x as Int: return T(x)

case let x as Double: return T(x)

default: fatalError("NumberConvertible convert failed!") } }}

Page 7: Generics and Inference

Cast by Inference!let number = 5.5

let a: Float = number.convert()let b: Int = number.convert()let c: Double = number.convert()

let aa = number.convert() + Float(2)let bb = number.convert() + Int(2)let cc = number.convert() + Double(2)

Page 8: Generics and Inference

Ex 2. Encoding/Decoding Structs(Map and Inferences)

Page 9: Generics and Inference

protocol Serializable { init(construct: [String: Any]) func destruct() -> [String: Any]}

extension Optional { func unbox<T>() -> T? { return self as? T } func unboxArray<T>() -> [T] { return unbox() ?? [] }}

Page 10: Generics and Inference

struct SortItem { let name: String let subSorts: [SortItem]}

extension SortItem: Serializable {

func destruct() -> [String: Any] { var construct = [String: Any]() construct["name"] = name construct["subSorts"] = subSorts.map { $0.destruct() } return construct }

init(construct: [String: Any]) { name = construct["name"].unbox() ?? ""

let sorts = construct["subSorts"] .unboxArray() !.map(SortItem.init)

}}

Page 11: Generics and Inference

struct SortItem { let name: String let subSorts: [SortItem]}

extension SortItem: Serializable {

func destruct() -> [String: Any] { var construct = [String: Any]() construct["name"] = name construct["subSorts"] = subSorts.map { $0.destruct() } return construct }

init(construct: [String: Any]) { name = construct["name"].unbox() ?? ""

let sorts = construct["subSorts"] .unboxArray() !.map(SortItem.init(construct:))

}}

Page 12: Generics and Inference

struct SortItem { let name: String let subSorts: [SortItem] //Default Value = Incognito init(subSorts: [SortItem] = [], name: String) { self.subSorts = subSorts self.name = name }}extension SortItem: Serializable {

func destruct() -> [String: Any] { var construct = [String: Any]() construct["name"] = name construct["subSorts"] = subSorts.map { $0.destruct() } return construct }

init(construct: [String: Any]) { name = construct["name"].unbox() ?? ""

let sorts = construct["subSorts"] .unboxArray() !.map(SortItem.init)

}}

Page 13: Generics and Inference

struct SortItem { let name: String let subSorts: [SortItem] //Default Value = Incognito init(subSorts: [SortItem] = [], name: String) { self.subSorts = subSorts self.name = name }}extension SortItem: Serializable {

func destruct() -> [String: Any] { var construct = [String: Any]() construct["name"] = name construct["subSorts"] = subSorts.map { $0.destruct() } return construct }

init(construct: [String: Any]) { name = construct["name"].unbox() ?? ""

let sorts = construct["subSorts"] .unboxArray() .map(SortItem.init) subSorts = sorts }}

Page 14: Generics and Inference

Return type of unboxArray() inferred through .map!

let sorts = construct["subSorts"] .unboxArray() .map(SortItem.init(construct:))

Page 15: Generics and Inference

Ex 3: Promises/Networking

Page 16: Generics and Inference

Result/Promise→ Concise implementation

→ Result Enum→ Promise Class w/AssociateType

Page 17: Generics and Inference

enum Result<T> { case error(BasicError), some(T)

private func fire(target: Promise<T>) { switch self { case .error(let err): target.failedAction?(err) case .some(let val): target.completeAction?(val) } }}

Page 18: Generics and Inference

final class Promise<T> { private var completeAction: (T -> Void)? private var failedAction: (BasicError -> Void)?

func complete(action: T! -> Void) -> Promise<T> { completeAction = action return self } func failure(action: BasicError -> Void) -> Promise<T> { failedAction = action return self } var trigger: Result<T>? { didSet { trigger?.fire(self) } }}

Closure keeps Promise alive - waiting for trigger

Page 19: Generics and Inference

Usage Example:(Networking + Generics * Inference)

Page 20: Generics and Inference

Promise on the Network:func getUser(url: String) -> Promise<User> {

}

Page 21: Generics and Inference

Promise on the Network:func getUser(url: String) -> Promise<User> { let promise = Promise<User>()

return promise}

Page 22: Generics and Inference

Promise on the Network:func getUser(url: String) -> Promise<User> { let promise = Promise<User>()

//Async call keeping reference to ˆpromiseˆ makeGetRequest(url) { response in

} return promise}

Page 23: Generics and Inference

Promise on the Network:func getUser(url: String) -> Promise<User> { let promise = Promise<User>()

//Async call keeping reference to ˆpromiseˆ makeGetRequest(url) { response in guard let json = response else { Promise.trigger = Result.error(.unknown) return }

} return promise}

Page 24: Generics and Inference

Promise on the Network:func getUser(url: String) -> Promise<User> { let promise = Promise<User>()

//Async call keeping reference to ˆpromiseˆ makeGetRequest(url) { response in guard let json = response else { Promise.trigger = Result.error(.unknown) return } if let user = try? User(object: json) { Promise.trigger = Result.some(user) }

} return promise}

Page 25: Generics and Inference

Promise on the Network:func getUser(url: String) -> Promise<User> { let promise = Promise<User>()

//Async call keeping reference to ˆpromiseˆ makeGetRequest(url) { response in guard let json = response else { Promise.trigger = Result.error(.unknown) return } if let user = try? User(object: json) { Promise.trigger = Result.some(user) } else { let error = BasicError(object: json) Promise.trigger = Result.error(error) } } return promise}

Page 26: Generics and Inference

More Generics and Inferred Promisesfunc getEncodableType<T: JSONDecodable>(url: String) -> Promise<T> { let promise = Promise<T>()

//Async call keeping reference to ˆpromiseˆ makeGetRequest(url) { response in guard let json = response else { Promise.trigger = Result.error(.unknown) return } if let result = try? T(object: json) { Promise.trigger = Result.some(result) } else { let error = BasicError(object: json) Promise.trigger = Result.error(error) } } return promise}

Page 27: Generics and Inference

More Generics and Inferred Promisesfunc getEncodableType<T: JSONDecodable>(url: String) -> Promise<T> { let promise = Promise<T>() //Generic instead of User

//Async call keeping reference to ˆpromiseˆ makeGetRequest(url) { response in guard let json = response else { Promise.trigger = Result.error(.unknown) return } if let result = try? T(object: json) { //JSONDecodable init Promise.trigger = Result.some(result) } else { let error = BasicError(object: json) Promise.trigger = Result.error(error) } } return promise}

Page 28: Generics and Inference

var user:User?var guest:Guest?

func fetchPeople() { let printError: BasicError -> Void = {"error: \($0.message)"}

NetworkService.getEncodableType("/url/User") .complete { user = $0 } .failure(printError)

NetworkService.getEncodableType("/url/Guest") .complete { guest = $0 } .failure(printError)}

Page 29: Generics and Inference

Promise<T> inferred by complete:(T)->Void

NetworkService.getEncodableType("/url/User") .complete { user = $0 }

Page 30: Generics and Inference

New in Swift 3 GenericsGeneric typealias

typealias StringDictionary<T> = Dictionary<String, T>typealias BackwardTriple<T1,T2,T3> = (T3, T2, T1)

Limited: Generic closure Crashes Playground

typealias StringDictionaryValue<T> = (Dictionary<String, T>) -> T?let testValue: StringDictionaryValue = { return $0["test"] }

Page 31: Generics and Inference

New in Swift 3 GenericsGeneric typealias

typealias StringDictionary<T> = Dictionary<String, T>typealias BackwardTriple<T1,T2,T3> = (T3, T2, T1)

Function Works as Expected

typealias StringDictionary<T> = (Dictionary<String, T>)func valueForKey<T>(dict:StringDictionary<T>, key: String) -> T? { return dict[key]}

Page 32: Generics and Inference

Inference Concluded

Page 33: Generics and Inference

1. Return Type Context

func convert<T: NumberConvertible>() -> T

2. Though map Function

.unboxArray().map(SortItem.init(construct:))

3. Through associatedtype Context

func complete(action: T! -> Void) -> Promise<T>

Page 34: Generics and Inference

Thank YouForward Swift

@RGfox