Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Brian Gesiak | Swift API Design: Getting Results

Brian Gesiak | Swift API Design: Getting Results

Presented at www.swiftsummit.com

Swift Summit

March 21, 2015
Tweet

More Decks by Swift Summit

Other Decks in Programming

Transcript

  1. @interface Banana : NSObject /** Whether the banana is peeled.

    */ @property (readonly) BOOL peeled; /** Whether the banana is delicious. @warning Do not use before the banana is peeled. */ @property (readonly) BOOL delicious; @end
  2. @interface Banana : NSObject /** Whether the banana is peeled.

    */ @property (readonly) BOOL peeled; /** Whether the banana is delicious. @warning Do not use before the banana is peeled. */ @property (readonly) BOOL delicious; @end
  3. @interface Banana : NSObject /** Whether the banana is peeled.

    */ @property (readonly) BOOL peeled; /** Whether the banana is delicious. @warning Do not use before the banana is peeled. */ @property (readonly) BOOL delicious; @end
  4. @interface Banana : NSObject /** Whether the banana is peeled.

    */ @property (readonly) BOOL peeled; /** Whether the banana is delicious. @warning Do not use before the banana is peeled. */ @property (readonly) BOOL delicious; @end
  5. BKBanana *banana = [[BKBanana alloc] init]; if (banana.delicious) { //

    ... } Caught "NSInternalInconsistencyException" º
  6. enum Banana { /** An unpeeled banana has no taste.

    */ case Unpeeled /** A peeled banana has a boolean to indicate whether it's delicious. */ case Peeled(delicious: Bool) }
  7. enum Banana { /** An unpeeled banana has no taste.

    */ case Unpeeled /** A peeled banana has a boolean to indicate whether it's delicious. */ case Peeled(delicious: Bool) }
  8. enum Banana { /** An unpeeled banana has no taste.

    */ case Unpeeled /** A peeled banana has a boolean to indicate whether it's delicious. */ case Peeled(delicious: Bool) }
  9. let banana = Banana.Unpeeled switch banana { case .Unpeeled: //

    ... case .Peeled(let delicious): if (delicious) { // ... } }
  10. let banana = Banana.Unpeeled switch banana { case .Unpeeled: //

    ... case .Peeled(let delicious): if (delicious) { // ... } }
  11. let banana = Banana.Unpeeled switch banana { case .Unpeeled: //

    ... case .Peeled(let delicious): if (delicious) { // ... } }
  12. Banana [[ if } let banana = Banana.Unpeeled switch banana

    { case .Unpeeled: // ... case .Peeled(let delicious): if (delicious) { // ... } }
  13. @interface MonkeyDB : NSObject /** Creates a database backed by

    the store at the given URL. */ - (instancetype)initWithURL:(NSURL *)url; /** Loads a monkey with the given name, or nil if one doesn't exist. */ - (Monkey *)monkeyWithName:(NSString *)name error:(NSError **)error; @end
  14. @interface MonkeyDB : NSObject /** Creates a database backed by

    the store at the given URL. */ - (instancetype)initWithURL:(NSURL *)url; /** Loads a monkey with the given name, or nil if one doesn't exist. */ - (Monkey *)monkeyWithName:(NSString *)name error:(NSError **)error; @end
  15. @interface MonkeyDB : NSObject /** Creates a database backed by

    the store at the given URL. */ - (instancetype)initWithURL:(NSURL *)url; /** Loads a monkey with the given name, or nil if one doesn't exist. */ - (Monkey *)monkeyWithName:(NSString *)name error:(NSError **)error; @end
  16. @interface MonkeyDB (Tricycles) /** Looks up whether the given monkey

    owns a tricycle. If the monkey owns one, returns the tricycle. If not, returns nil. If an error occurs, the error pointer will be populated. */ - (Tricycle *)tricycleForMonkey:(Monkey *)monkey error:(NSError **)error; @end
  17. @interface MonkeyDB (Tricycles) /** Looks up whether the given monkey

    owns a tricycle. If the monkey owns one, returns the tricycle. If not, returns nil. If an error occurs, the error pointer will be populated. */ - (Tricycle *)tricycleForMonkey:(Monkey *)monkey error:(NSError **)error; @end
  18. NSURL *url = [NSURL fileURLWithPath:@".monkeydb"]; MonkeyDB *database = [[MonkeyDB alloc]

    initWithURL:url]; NSError *monkeyError = nil; Monkey *monkey = [database monkeyWithName:@"Peepers" error:&monkeyError]; if (monkey == nil || monkeyError != nil) { // ...error handling. return nil; } NSError *tricycleError = nil; Tricycle *tricycle = [database tricycleForMonkey:monkey error:&tricycleError];
  19. NSURL *url = [NSURL fileURLWithPath:@".monkeydb"]; MonkeyDB *database = [[MonkeyDB alloc]

    initWithURL:url]; NSError *monkeyError = nil; Monkey *monkey = [database monkeyWithName:@"Peepers" error:&monkeyError]; if (monkey == nil || monkeyError != nil) { // ...error handling. return nil; } NSError *tricycleError = nil; Tricycle *tricycle = [database tricycleForMonkey:monkey error:&tricycleError];
  20. NSURL *url = [NSURL fileURLWithPath:@".monkeydb"]; MonkeyDB *database = [[MonkeyDB alloc]

    initWithURL:url]; NSError *monkeyError = nil; Monkey *monkey = [database monkeyWithName:@"Peepers" error:&monkeyError]; if (monkey == nil || monkeyError != nil) { // ...error handling. return nil; } NSError *tricycleError = nil; Tricycle *tricycle = [database tricycleForMonkey:monkey error:&tricycleError];
  21. NSURL *url = [NSURL fileURLWithPath:@".monkeydb"]; MonkeyDB *database = [[MonkeyDB alloc]

    initWithURL:url]; NSError *monkeyError = nil; Monkey *monkey = [database monkeyWithName:@"Peepers" error:&monkeyError]; if (monkey == nil || monkeyError != nil) { // ...error handling. return nil; } NSError *tricycleError = nil; Tricycle *tricycle = [database tricycleForMonkey:monkey error:&tricycleError];
  22. // ...error handling. return nil; } NSError *tricycleError = nil;

    Tricycle *tricycle = [database tricycleForMonkey:monkey error:&tricycleError]; if (tricycle == nil || tricycleError != nil) { // ...error handling. return nil; } return tricycle.brandName;
  23. // ...error handling. return nil; } NSError *tricycleError = nil;

    Tricycle *tricycle = [database tricycleForMonkey:monkey error:&tricycleError]; if (tricycle == nil || tricycleError != nil) { // ...error handling. return nil; } return tricycle.brandName;
  24. // ...error handling. return nil; } NSError *tricycleError = nil;

    Tricycle *tricycle = [database tricycleForMonkey:monkey error:&tricycleError]; if (tricycle == nil || tricycleError != nil) { // ...error handling. return nil; } return tricycle.brandName;
  25. NSURL *url = [NSURL fileURLWithPath:@".monkeydb"]; MonkeyDB *database = [[MonkeyDB alloc]

    initWithURL:url]; Monkey *monkey = [database monkeyWithName:@"Peepers" error:nil]; Tricycle *tricycle = [database tricycleForMonkey:monkey error:nil]; return tricycle.brandName;
  26. NSURL *url = [NSURL fileURLWithPath:@".monkeydb"]; MonkeyDB *database = [[MonkeyDB alloc]

    initWithURL:url]; Monkey *monkey = [database monkeyWithName:@"Peepers" error:nil]; Tricycle *tricycle = [database tricycleForMonkey:monkey error:nil]; return tricycle.brandName; Caught "NSInternalInconsisntencyException" º
  27. NSURL *url = [NSURL fileURLWithPath:@".monkeydb"]; MonkeyDB *database = [[MonkeyDB alloc]

    initWithURL:url]; Monkey *monkey = [database monkeyWithName:@"Peepers" error:nil]; Tricycle *tricycle = [database tricycleForMonkey:monkey error:nil]; return tricycle.brandName; Thread 1: EXC_BAD_INSTRUCTION
  28. /** The result of an operation that could have failed.

    */ enum Result<SuccessType, ErrorType> { /** If the operation succeeded, the result has a value. */ case Success(SuccessType) /** If the operation failed, the result holds an error. */ case Failure(ErrorType) }
  29. /** The result of an operation that could have failed.

    */ enum Result<SuccessType, ErrorType> { /** If the operation succeeded, the result has a value. */ case Success(SuccessType) /** If the operation failed, the result holds an error. */ case Failure(ErrorType) }
  30. /** The result of an operation that could have failed.

    */ enum Result<SuccessType, ErrorType> { /** If the operation succeeded, the result has a value. */ case Success(SuccessType) /** If the operation failed, the result holds an error. */ case Failure(ErrorType) }
  31. struct MonkeyDB { init(url: NSURL) func monkey(name: String) -> Result<Monkey,

    NSError> func tricycle(monkey: Monkey) -> Result<Tricycle, NSError> }
  32. struct MonkeyDB { init(url: NSURL) func monkey(name: String) -> Result<Monkey,

    NSError> func tricycle(monkey: Monkey) -> Result<Tricycle, NSError> }
  33. struct MonkeyDB { init(url: NSURL) func monkey(name: String) -> Result<Monkey,

    NSError> func tricycle(monkey: Monkey) -> Result<Tricycle, NSError> }
  34. let monkeyResult = database.monkey(“Peepers") switch monkeyResult { case .Failure(let error):

    return .Failure(error) case .Success(let monkey): let tricycleResult = database.tricycle(monkey) switch tricycleResult { case .Failure(let error): return .Failure(error) case .Success(let tricycle): return .Success(tricycle.brandName) } }
  35. let monkeyResult = database.monkey(“Peepers") switch monkeyResult { case .Failure(let error):

    return .Failure(error) case .Success(let monkey): let tricycleResult = database.tricycle(monkey) switch tricycleResult { case .Failure(let error): return .Failure(error) case .Success(let tricycle): return .Success(tricycle.brandName) } }
  36. let monkeyResult = database.monkey(“Peepers") switch monkeyResult { case .Failure(let error):

    return .Failure(error) case .Success(let monkey): let tricycleResult = database.tricycle(monkey) switch tricycleResult { case .Failure(let error): return .Failure(error) case .Success(let tricycle): return .Success(tricycle.brandName) } }
  37. let monkeyResult = database.monkey(“Peepers") switch monkeyResult { case .Failure(let error):

    return .Failure(error) case .Success(let monkey): let tricycleResult = database.tricycle(monkey) switch tricycleResult { case .Failure(let error): return .Failure(error) case .Success(let tricycle): return .Success(tricycle.brandName) } }
  38. let monkeyResult = database.monkey(“Peepers") switch monkeyResult { case .Failure(let error):

    return .Failure(error) case .Success(let monkey): let tricycleResult = database.tricycle(monkey) switch tricycleResult { case .Failure(let error): return .Failure(error) case .Success(let tricycle): return .Success(tricycle.brandName) } }
  39. let monkeyResult = database.monkey(“Peepers") switch monkeyResult { case .Failure(let error):

    return .Failure(error) case .Success(let monkey): let tricycleResult = database.tricycle(monkey) switch tricycleResult { case .Failure(let error): return .Failure(error) case .Success(let tricycle): return .Success(tricycle.brandName) } }
  40. enum Result<SuccessType, ErrorType> { func map<NewType>(transform: SuccessType -> NewType) ->

    Result<NewType, ErrorType> func flatMap<NewType>( transform: SuccessType -> Result<NewType, ErrorType>) -> Result<NewType, ErrorType> }
  41. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  42. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  43. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  44. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  45. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  46. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  47. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  48. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  49. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  50. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  51. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  52. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  53. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  54. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  55. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  56. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  57. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult
  58. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult let tricycleResult = monkeyResult.flatMap { return database.tricycle($0) }
  59. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { (monkey:

    Monkey) in return database.tricycle(monkey) } let brandNameResult = tricycleResult.map { (tricycle: Tricycle) in return tricycle.brandName } return brandNameResult let tricycleResult = monkeyResult.flatMap { return database.tricycle($0) } let brandNameResult = tricycleResult.map { return $0.brandName }
  60. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { return

    database.tricycle($0) } let brandNameResult = tricycleResult.map { return $0.brandName } return brandNameResult
  61. let monkeyResult = database.monkey("Peepers") let tricycleResult = monkeyResult.flatMap { return

    database.tricycle($0) } let brandNameResult = tricycleResult.map { return $0.brandName } return brandNameResult let brandNameResult = tricycleResult.map { $0.brandName } let tricycleResult = monkeyResult.flatMap { database.tricycle($0) }
  62. let url = NSURL( fileURLWithPath: "/Users/modocache/Gift")! let latestCommitMessage = openRepository(url)

    .flatMap { $0.headReference } .flatMap { $0.commit } .flatMap { $0.message } switch latestCommitMessage { case .Success(let message): println(message) case .Failure(let error): println(error.localizedDescription) }
  63. let url = NSURL( fileURLWithPath: "/Users/modocache/Gift")! let latestCommitMessage = openRepository(url)

    .flatMap { $0.headReference } .flatMap { $0.commit } .flatMap { $0.message } switch latestCommitMessage { case .Success(let message): println(message) case .Failure(let error): println(error.localizedDescription) }
  64. let url = NSURL( fileURLWithPath: "/Users/modocache/Gift")! let latestCommitMessage = openRepository(url)

    .flatMap { $0.headReference } .flatMap { $0.commit } .flatMap { $0.message } switch latestCommitMessage { case .Success(let message): println(message) case .Failure(let error): println(error.localizedDescription) }
  65. let url = NSURL( fileURLWithPath: "/Users/modocache/Gift")! let latestCommitMessage = openRepository(url)

    .flatMap { $0.headReference } .flatMap { $0.commit } .flatMap { $0.message } switch latestCommitMessage { case .Success(let message): println(message) case .Failure(let error): println(error.localizedDescription) }
  66. let url = NSURL( fileURLWithPath: "/Users/modocache/Gift")! let latestCommitMessage = openRepository(url)

    .flatMap { $0.headReference } .flatMap { $0.commit } .flatMap { $0.message } switch latestCommitMessage { case .Success(let message): println(message) case .Failure(let error): println(error.localizedDescription) }
  67. openRepository(url) .flatMap { $0.index } .flatMap { $0.add() } .flatMap

    { $0.writeTree() } .flatMap { $0.commit("This is bananas!") } git commit --all --message "this is bananas"
  68. openRepository(url) .flatMap { $0.index } .flatMap { $0.add() } .flatMap

    { $0.writeTree() } .flatMap { $0.commit("This is bananas!") } git commit --all --message "this is bananas"
  69. openRepository(url) .flatMap { $0.index } .flatMap { $0.add() } .flatMap

    { $0.writeTree() } .flatMap { $0.commit("This is bananas!") } git commit --all --message "this is bananas"
  70. openRepository(url) .flatMap { $0.index } .flatMap { $0.add() } .flatMap

    { $0.writeTree() } .flatMap { $0.commit("This is bananas!") } git commit --all --message "this is bananas"
  71. openRepository(url) .flatMap { $0.index } .flatMap { $0.add() } .flatMap

    { $0.writeTree() } .flatMap { $0.commit("This is bananas!") } git commit --all --message "this is bananas"
  72. enum Result<SuccessType, ErrorType> { func map<NewType>(transform: SuccessType -> NewType) ->

    Result<NewType, ErrorType> func flatMap<NewType>( transform: SuccessType -> Result<NewType, ErrorType>) -> Result<NewType, ErrorType> }
  73. enum Result<SuccessType, ErrorType> { func map<NewType>(transform: SuccessType -> NewType) ->

    Result<NewType, ErrorType> func flatMap<NewType>( transform: SuccessType -> Result<NewType, ErrorType>) -> Result<NewType, ErrorType> }
  74. enum Result<SuccessType, ErrorType> { func map<NewType>(transform: SuccessType -> NewType) ->

    Result<NewType, ErrorType> func flatMap<NewType>( transform: SuccessType -> Result<NewType, ErrorType>) -> Result<NewType, ErrorType> }
  75. enum Result<SuccessType, ErrorType> { func map<NewType>(transform: SuccessType -> NewType) ->

    Result<NewType, ErrorType> func flatMap<NewType>( transform: SuccessType -> Result<NewType, ErrorType>) -> Result<NewType, ErrorType> }
  76. enum Result<SuccessType, ErrorType> { func map<NewType>(transform: SuccessType -> NewType) ->

    Result<NewType, ErrorType> func flatMap<NewType>( transform: SuccessType -> Result<NewType, ErrorType>) -> Result<NewType, ErrorType> }
  77. enum Result<SuccessType, ErrorType> { func map<NewType>(transform: SuccessType -> NewType) ->

    Result<NewType, ErrorType> func flatMap<NewType>( transform: SuccessType -> Result<NewType, ErrorType>) -> Result<NewType, ErrorType> }
  78. enum Result<SuccessType, ErrorType> { func map<NewType>(transform: SuccessType -> NewType) ->

    Result<NewType, ErrorType> func flatMap<NewType>( transform: SuccessType -> Result<NewType, ErrorType>) -> Result<NewType, ErrorType> }