Share
Embed
Dobry zwyczaj: nie odziedziczaj
Slides for my conference talk from Mobilization 2015, 2015/10/17.
Polish only.
English title would be "Solely on merit: do not inherit"
Krzysztof Siejkowski
October 17, 2015
Transcript
47 slides
-
struct SomeStruct {} enum SomeEnum {} typealias SomeFunction = (Int
-> String) class C : SomeFunction ❗ Inheritance from non-protocol, non-class type 'SomeFunction' -
protocol SessionAware protocol LocationAware protocol FavouritesFetchable class MyViewController : UIViewController,
SessionAware, LocationAware, FavouritesFetchable -
protocol SessionAware { func login(username: String, _ password: String, _
callback: (UserDetails) -> ()) } extension MyViewController : SessionAware {} extension SessionAware { func login(username: String, _ password: String, _ callback: (UserDetails) -> ())) { // domyślna implementacja } } ❗ http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future -
protocol FavouritesDataSource : UITableViewDataSource { var state: [FavouriteDetails] { get
} // "obietnica" stanu } extension FavouritesDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return state.count // ... protocol FavouritesTableDelegate : UITableViewDelegate { var state: [FavouriteDetails] { get } // "obietnica" stanu } extension FavouritesTableDelegate { func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { // ... class MyViewController : NSObject, FavouritesDataSource, FavouritesTableDelegate { var state: [FavouriteDetails] = Array() init(newState: [FavouriteDetails]) { state = newState } -
func login(username: String, _ password: String, _ callback: (UserDetails) ->
()) func update(view: HeaderView) (_ user: UserDetails) -> UserDetails func fetchFavourites(user: UserDetails) (_ callback: (FavouritesData) -> ()) func update(source: FavoritesDataSource) (_ tableView: UITableView) (_ favourites: FavouritesData) -
class SomeViewController { let updateHeader = update(headerView) let updateFavourites =
update(favouritesDataSource)(tableView) override func viewDidLoad() { // ..., m.in super.viewDidLoad() login("siejkowski","mobilization") { details in fetchFavourites(updateHeader(details))(updateFavourites) } } -
infix operator |> { associativity left } infix operator <|
{ associativity right } public func |> <A, B>(a : A, f : A -> B) -> B { return f(a) } public func <| <A, B>(f : A -> B, a : A) -> B { return f(a) } -
login("siejkowski","mobilization") { details in fetchFavourites(updateHeader(details))(updateFavourites) } ⬇ ⬇ ⬇ login("siejkowski","mobilization")
{ details in (details |> updateHeader |> fetchFavourites) <| updateFavourites } -
class SomeViewController { let updateHeader = update(headerView) let updateFavourites =
update(favouritesDataSource)(tableView) override func viewDidLoad() { super.viewDidLoad() login("siejkowski","mobilization") { details in (details |> updateHeader |> fetchFavourites) <| updateFavourites } } ! -
struct FunctionUsingStruct { let func: String -> Bool init(_ injectedFunc:
String -> Bool) { // funkcje można wstrzykiwać func = injectedFunc ... } } ! -
class DIFactory { func realFunc(string: String) -> Bool { ...
} // w produkcyjnym kodzie wstrzykujemy prawdziwą funkcję func functionUsingStruct() -> FunctionUsingStruct { return FunctionUsingStruct(realFunc) } class TestCase { func testFunc(string: String) -> Bool { return true } // w testowym kodzie używamy mockowej funkcji let testStruct = FunctionUsingStruct(testFunc) ! -
func login(username: String, _ password: String, _ callback: (UserDetails) ->
()) func fullLogin(loginManager: LoginManager) (_ username: String, _ password: String, _ callback(UserDetails) -> ()) -> () { loginManager.login(username, password, callback) } let login = fullLogin(actualLoginManager) let mockLogin = fullLogin(mockLoginManager) -
extension MyViewController : SessionAware { func login(username: String, _ password:
String, _ callback: (UserDetails) -> ()) { // tutaj przekazany jest domyślnie self } } func login(username: String, _ password: String, _ callback: (UserDetails) -> ()) { // tutaj przekazane jest to co w sygnaturze } -
func root(double: Double) -> Double? { ... } func root(float:
Float) -> Float? { ... } func root(int: Int) -> Int? { ... } protocol Rootable { func root() -> Self? } extension Double : Rootable { ... } extension Float : Rootable { ... } extension Int : Rootable { ... } func useRootable(rootable: Rootable) { rootable.root() } -
*-able protocol JSONDecodable { static func decode(json: JSON) -> Self
} protocol Validatable { func validate(validator: Validator) -> Bool } protocol Hashable : Equatable { public var hashValue: Int { get } } -
func canCauseProblem(input: Int) -> ProblemHiding<String> func possibleProblem(input: String) -> ProblemHiding<Double>
func yetAnotherProblem(input: Double) -> ProblemHiding<Int> let input = 42 ProblemHiding(input) // udajemy że wszystko gra .execute(canCauseProblem) // jakby nic się nie stało .execute(possibleProblem) // bez nerwów, bez ifów .execute(yetAnotherProblem) // jak kwiat lotosu .obtainValue() // sprawdzam! -
protocol Monad { typealias A typealias B typealias FB func
bind(f: A -> FB) -> FB } ! -
extension Optional : Monad { typealias A = Wrapped typealias
B = Any // nil jest problemem typealias FB = B? func bind<B>(f: A -> B?) -> B? { return self.flatMap(f) } } extension Array : Monad { typealias A = Element typealias B = Any // wiele wartości to problem typealias FB = Array<B> func bind<B>(f: A -> [B]) -> [B] { return self.flatMap(f) } } -
enum Result<Value> { // możliwy ErrorType to problem case Success(Value)
case Failure(ErrorType) } extension Result : Monad { typealias A = Value typealias B = Any typealias FB = Result<B> func bind<B>(f: A -> Result<B>) -> Result<B> { switch self { case .Success(let value): return f(value) case .Failure(let error): return .Failure(error) } } }