Created
September 18, 2015 16:19
-
-
Save thilo11/b8a0cf19f0afd2e113b7 to your computer and use it in GitHub Desktop.
The Xcode 7 playground for the Swift Meetup "Protocol-Oriented Programming in Swift" http://www.meetup.com/de/Swift-Meetup-Hamburg/events/224604913/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import XCPlayground | |
import Foundation | |
// in Xcode 7 use Editor/Show Rendered Markup to display the formatted comments | |
//: # First things first: The Protocols | |
//: It is good Swift practice to start with your protocols | |
//: Instead of a common base classes we define protocols | |
protocol Hardware { | |
var name: String {get} | |
var vendor: String {get} | |
func fullName () -> String | |
} | |
protocol ProgrammingLanguage { | |
var name:String {get} | |
var inventedIn:Int {get} | |
var inventors:[String] {get} | |
func numberOfInventors () -> Int | |
} | |
//: A cross cutting concern. We want to use loggers everywhere | |
protocol Logger { | |
func log(message:String) -> () | |
} | |
//: A protocol with a 'Self' requirement. | |
protocol History { | |
func isInfluencedBy(other: Self) -> Bool | |
} | |
func >(lhs: ProgrammingLanguage, rhs: ProgrammingLanguage) -> Bool { | |
return lhs.inventedIn > rhs.inventedIn | |
} | |
func ==(lhs: ProgrammingLanguage, rhs: ProgrammingLanguage) -> Bool { | |
return lhs.inventedIn == rhs.inventedIn | |
} | |
//: # Protocol Extensions | |
//: Let's implement some default behaviour | |
extension ProgrammingLanguage { | |
func numberOfInventors () -> Int { | |
return inventors.count | |
} | |
} | |
//: Cool! We can access self. Compare to Java 8 Virtual Extension Methods | |
extension Logger { | |
func log(message:String) -> (){ | |
print ("log msg: \(self.dynamicType): \(message)") | |
} | |
} | |
//: Even cooler: Declare conditions on the type | |
extension Logger where Self: ProgrammingLanguage { | |
func prettyLog(message:String) -> (){ | |
print ("nice log msg: \(NSDate()) \(self.dynamicType): \(message)") | |
} | |
} | |
//: # Finally our structs | |
//: No (mutable) classes any more. We use structs (Value Types) | |
struct ComputerHardware: Hardware, Logger { | |
var name: String | |
var vendor: String | |
func fullName () -> String { | |
log("only simple logging allowed here") | |
return "\(vendor): \(name)" | |
} | |
} | |
//: No inheritance tree, we only 'mixin' the stuff we need | |
struct OoLanguage: ProgrammingLanguage, Logger { | |
let name:String | |
let inventors:[String] | |
let inventedIn: Int | |
let hasMultipleInheritance:Bool | |
} | |
struct FunctionalLanguage: ProgrammingLanguage, History, Logger { | |
let name: String | |
let inventors: [String] | |
let inventedIn: Int | |
let hasHighOrderFunctions: Bool | |
let hasImmutableCollections: Bool | |
func isInfluencedBy(other: FunctionalLanguage) -> Bool { | |
return self.inventedIn > other.inventedIn | |
} | |
func isCool() -> Bool { | |
prettyLog("fancy logging here") | |
return hasHighOrderFunctions && hasImmutableCollections | |
} | |
} | |
// doesn't work | |
//func doSomething(languages:[History]) -> [History]{ | |
// return [] | |
//} | |
// works using Generic Type, Self Requirement! | |
func doSomething<T:History>(languages:[T]) -> [T]{ | |
return [languages.first!] | |
} | |
//: # Our Objects | |
let lispMachine = ComputerHardware(name: "3070", vendor: "Symbolics") | |
let clojure = FunctionalLanguage(name: "Clojure", inventors: ["Rich Hickey"], inventedIn: 2007, hasHighOrderFunctions: true, hasImmutableCollections: true) | |
let erlang = FunctionalLanguage(name: "Erlang", inventors: ["Joe Armstrong, Robert Virding, Mike Williams"], inventedIn: 1986, hasHighOrderFunctions: true, hasImmutableCollections: true) | |
let smalltalk = OoLanguage(name:"Smalltalk", inventors:["Alan Kay", "Dan Ingalls", "Adele Goldberg"], inventedIn: 1971, hasMultipleInheritance: false) | |
//: Does the extension work? | |
smalltalk.numberOfInventors() | |
clojure.numberOfInventors() | |
//: Does our logger work? | |
lispMachine.fullName() // simple logger | |
clojure.isCool() // fancy logger | |
//: protocols are types | |
let progLanguages:[ProgrammingLanguage] = [clojure, erlang, smalltalk] | |
let progLangNames = progLanguages.map({(lang) -> String in return lang.name}) | |
progLangNames | |
clojure.isInfluencedBy(erlang) | |
progLanguages.sort(>) | |
doSomething([erlang, clojure]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment