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

具体例とクイズで学ぶ、Swiftの4種類のエラーの使い分け

Yuta Koshizawa
September 16, 2017
6k

 具体例とクイズで学ぶ、Swiftの4種類のエラーの使い分け

Yuta Koshizawa

September 16, 2017
Tweet

More Decks by Yuta Koshizawa

Transcript

  1. ۩ମྫͱΫΠζͰֶͿɺ
    Swi$ͷ4छྨͷΤϥʔͷ࢖͍෼͚
    Yuta Koshizawa @koher

    View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. Q. Swi' ͰΤϥʔΛදͦ͏ͱࢥͬͨ
    ͱ͖ʹԿΛ࢖͍·͔͢ʁ

    View Slide

  8. throw FooError()

    View Slide

  9. let number: Int? =
    Int(string)

    View Slide

  10. let foo: Foo? = try? foo()

    View Slide

  11. fatalError()

    View Slide

  12. assert(...)

    View Slide

  13. precondition(...)

    View Slide

  14. assertionFailure()

    View Slide

  15. preconditionFailure()

    View Slide

  16. fooOrNil!

    View Slide

  17. array[-1]

    View Slide

  18. Int.max + 1

    View Slide

  19. [Int](repeating: 42,
    count: Int.max)

    View Slide

  20. func foo() { foo() }

    View Slide

  21. throw FooError()
    let number: Int? = Int(String)
    let foo: Foo? = try? foo()
    fatalError()
    assert(...)
    assertionFailure()
    precondition(...)
    preconditionFailure()
    fooOrNil!
    array[-1]
    Int.max + 1
    [Int](repeating: 42, count: Int.max)
    func foo() { foo() }

    View Slide

  22. Javaͷ৔߹
    Throwable -+- Exception -+- RuntimeException -+- NullPointerException
    | | +- IndexOutOfBoundsException
    | | ...
    | |
    | +- IOException
    | +- SQLException
    | ...
    |
    +- Error - ... -+- OutOfMemoryError
    +- StackOverflowError
    ...

    View Slide

  23. throw FooError()
    let number: Int? = Int(string)
    let foo: Foo? = try? foo()
    fatalError()
    assert(...)
    assertionFailure()
    precondition(...)
    preconditionFailure()
    fooOrNil!
    array[-1]
    Int.max + 1
    [Int](repeating: 42, count: Int.max)
    func foo() { foo() }

    View Slide

  24. View Slide

  25. View Slide

  26. View Slide

  27. View Slide

  28. View Slide

  29. Simple domain errors
    Recoverable errors
    Universal errors
    Logic failures

    View Slide

  30. Simple domain errors

    View Slide

  31. let number: Int? =
    Int(string)

    View Slide

  32. Simple domain errors
    • ΦϖϨʔγϣϯ͕ࣦഊ͢Δલఏ৚͕݅໌֬
    • ੒ޭ͔ࣦͨ͠ഊ͔͕ͨ͠෼͔Ε͹े෼
    • Swi% Ͱ͸ Optional Λฦ͢͜ͱͰද͢

    View Slide

  33. let element: Int? =
    array.first

    View Slide

  34. let value =
    dictionary["unknownKey"]

    View Slide

  35. Recoverable errors

    View Slide

  36. try fileManager
    .removeItem(at: url)

    View Slide

  37. Recoverable errors
    • ༷ʑͳݪҼͰΦϖϨʔγϣϯ͕ࣦഊ͢Δ
    • ࣦഊͷݪҼΛ஌Γ͍ͨ
    • ݪҼผʹϋϯυϦϯά͍ͨ͠
    • Swi% Ͱ͸ Error Λ throw ͢Δ͜ͱͰද͢

    View Slide

  38. ճ෮ՄೳͳΤϥʔ
    Simple domain errors
    Recoverable errors

    View Slide

  39. ճ෮ෆೳͳΤϥʔ
    Universal errors
    Logic failures

    View Slide

  40. Universal errors

    View Slide

  41. [Int](repeating: 42,
    count: Int.max)

    View Slide

  42. Universal error ͕ϋϯυϦϯάՄೳͩͬͨͱ͢Δͱ
    // ϝϞϦෆ଍ͷϋϯυϦϯάͷྫ
    let foo: Foo? = allocate(size(of: Foo))
    guard let foo = foo else {
    // Τϥʔϝοηʔδͷੜ੒Ͱ͞ΒʹϝϞϦෆ଍͕ى͜Δ͔΋
    showAlert("ϝϞϦ͕଍Γ·ͤΜɻ")
    }

    View Slide

  43. func foo() { foo() }

    View Slide

  44. Ctrl + C

    View Slide

  45. thread.cancel()

    View Slide

  46. Universal errors
    • ίʔυதͷࢸΔͱ͜ΖͰൃੜ͢Δ΋ͷ͕ଟ͍
    • ϋϯυϦϯά͠Α͏͕ͳ͍
    • ίʔυ͔Βൃੜͤ͞Δʹ͸ NSException ʢ·ͨ͸
    fatalError ʣ

    View Slide

  47. Logic failures

    View Slide

  48. fooOrNil!

    View Slide

  49. Int.max + 1

    View Slide

  50. array[-1]

    View Slide

  51. Array ͷ subscript ͷࣦഊ͕ Logic failure ͳཧ༝
    // [Int] Λιʔτ͢Δؔ਺
    func sort(_ ns: inout [Int]) {
    for i in 0 ..< ns.count {
    for j in i + 1 ..< ns.count {
    if ns[j] < ns[i] {
    let t = ns[j]
    ns[j] = ns[i]
    ns[i] = t
    }
    }
    }
    }

    View Slide

  52. Array ͷ subscript ͷࣦഊ͕ Logic failure ͳཧ༝
    // [Int] Λιʔτ͢Δؔ਺
    func sort(_ ns: inout [Int]) {
    for i in 0 ..< ns.count {
    for j in i + 1 ..< ns.count {
    if ns[j] < ns[i] {
    let t = ns[j]
    ns[j] = ns[i]
    ns[i] = t
    }
    }
    }
    }

    View Slide

  53. Array ͷ subscript ͷࣦഊ͕ Logic failure ͳཧ༝
    // ..< Λ ... ʹͯ͠͠·͏ͱΠϯσοΫε͕͸Έग़ͯΤϥʔ
    func sort(_ ns: inout [Int]) {
    for i in 0 ... ns.count {
    for j in i + 1 ... ns.count {
    if ns[j] < ns[i] {
    let t = ns[j]
    ns[j] = ns[i]
    ns[i] = t
    }
    }
    }
    }

    View Slide

  54. Array ͷ subscript ͷࣦഊ͕ Logic failure ͳཧ༝
    // Ͱ΋ɺ͜͜Ͱ nil ͕ฦ͖ͬͯͯ΋ϋϯυϦϯά͠Α͏͕ͳ͍
    func sort(_ ns: inout [Int]) {
    for i in 0 ... ns.count {
    for j in i + 1 ... ns.count {
    if ns[j] < ns[i] {
    let t = ns[j]
    ns[j] = ns[i]
    ns[i] = t
    }
    }
    }
    }

    View Slide

  55. Array ͷ subscript ͷࣦഊ͕ Logic failure ͳཧ༝
    // Ͳ͏ͤ ! ͢Δ͜ͱʹͳͬͯແବ
    func sort(_ ns: inout [Int]) {
    for i in 0 ... ns.count {
    for j in i + 1 ... ns.count {
    if ns[j]! < ns[i]! {
    let t = ns[j]!
    ns[j] = ns[i]!
    ns[i] = t
    }
    }
    }
    }

    View Slide

  56. Logic failures
    • ίʔυͷϛεʹΑͬͯൃੜ
    • ࣮ߦ࣌Ͱ͸ͳ͘ίʔυͷमਖ਼ʹΑͬͯରԠ
    • precondition, assert ͳͲͰൃੜͤ͞Δ

    View Slide

  57. ؔ਺ -Onone -O -Ounchecked
    fatalError ○ ○ ○
    precondi/on ○ ○
    assert ○
    ※ ○͕෇͍͍ͯͳ͍૊Έ߹Θͤ͸νΣοΫ͕লུ͞ΕΔ

    View Slide

  58. precondition ͩͱ͏Ε͍͠ཧ༝
    // [Int] Λιʔτ͢Δؔ਺
    func sort(_ ns: inout [Int]) {
    for i in 0 ..< ns.count {
    for j in i + 1 ..< ns.count {
    if ns[j] < ns[i] {
    let t = ns[j]
    ns[j] = ns[i]
    ns[i] = t
    }
    }
    }
    }

    View Slide

  59. precondition ͩͱ͏Ε͍͠ཧ༝
    // [Int] Λιʔτ͢Δؔ਺
    func sort(_ ns: inout [Int]) {
    for i in 0 ..< ns.count {
    for j in i + 1 ..< ns.count {
    if ns[j] < ns[i] {
    let t = ns[j]
    ns[j] = ns[i]
    ns[i] = t
    }
    }
    }
    }

    View Slide

  60. precondition ͩͱ͏Ε͍͠ཧ༝
    // guard ͱ fatalError ͰΠϯσοΫεͷνΣοΫ
    struct Array {
    subscript(index: Int): Element {
    get {
    guard 0 <= index && index < count else {
    fatalError()
    }
    ...
    }
    set { ... }
    }
    }

    View Slide

  61. precondition ͩͱ͏Ε͍͠ཧ༝
    // guard ͱ fatalError ͰΠϯσοΫεͷνΣοΫ
    struct Array {
    subscript(index: Int): Element {
    get {
    guard 0 <= index && index < count else {
    fatalError()
    }
    ...
    }
    set { ... }
    }
    }

    View Slide

  62. precondition ͩͱ͏Ε͍͠ཧ༝
    // precondition ͸ -Ounchecked ͰऔΓআ͔ΕΔ
    struct Array {
    subscript(index: Int): Element {
    get {
    precondition(0 <= index && index < count)
    ...
    }
    set { ... }
    }
    }

    View Slide

  63. -Onone ͷͱ͖ͷڍಈ
    // arrayindex.swift
    let a = [2, 3, 5]
    print(a[3])
    $ swift arrayindex.swift
    fatal error: Index out of range

    View Slide

  64. -Ounchecked ͷͱ͖ͷڍಈ
    // arrayindex.swift
    let a = [2, 3, 5]
    print(a[3])
    $ swift -Ounchecked arrayindex.swift
    2392130230941712

    View Slide

  65. -Ounchecked ͷͱ͖ͷڍಈ
    let a: Int? = nil
    print(a!) // ࣮ߦ࣌ΤϥʔʹͳΒͳ͍
    let b: UInt8 = 255
    print(b + 1) // ࣮ߦ࣌ΤϥʔʹͳΒͳ͍

    View Slide

  66. Logic failure ͸ίʔυͷϛεͷΑͬ
    ͯҾ͖ى͜͞ΕΔ

    ίʔυͷϛε͕ͳ͚Ε͹ Logic
    failure ͸ى͜Βͳ͍

    View Slide

  67. assert ͷ࢖༻ྫ
    assert ͸಺෦తͳ੔߹ੑͷνΣοΫʹ࢖͏
    import TensorSwift
    // 10000 ਓ෼ͷ྆खͷࢦͷ௕͞
    let tensor = Tensor(shape: [10000, 2, 5], elements: ...)
    // [ਓ, ࠨӈ, ࢦ] ͔Β [ࢦ, ਓ, ࠨӈ] ʹม׵
    let transposed = tensor.transposed([2, 0, 1])
    // ࠨखͷσʔλ͚ͩΛऔΓग़͢
    let lefthand = tensor[..., ..., 1]
    // [ࢦ, ਓ] ͷॱʹͳ͍ͬͯͯ΄͍͚͠Ͳॲཧ͕ෳࡶͰࣗ৴͕࣋ͯͳ͍ͷͰνΣοΫ
    assert(lefthand.shape == [5, 10000])

    View Slide

  68. Simple domain errors
    Recoverable errors
    Universal errors
    Logic failures

    View Slide

  69. ΤϥʔͷछྨͷܾΊํ
    ͲΜͳ಺༰ͷΤϥʔ͔
    ͲͷΑ͏ʹΤϥʔϋϯυϦϯά͍͔ͤͨ͞

    View Slide

  70. // Simple domain error Ͱͳ͘ Recoverable Ͱ͋ͬͯ΄͍͠
    let string = "99999999999999999999999999"
    ...
    do {
    let number: Int = try Int(string)
    } catch is OverflowError {
    showAlert("\(Int.min) - \(Int.max) ͷ஋Λೖྗͯ͠Լ͍͞ɻ")
    } catch {
    showAlert("੔਺Λೖྗͯ͠Լ͍͞ɻ")
    }

    View Slide

  71. // Universal error Ͱ͸ͳ͘ Simple domain error Ͱ͋ͬͯ΄͍͠
    guard let a = malloc(MemoryLayout.size * 100_000_000) else {
    showAlert("ϝϞϦ͕଍Γ·ͤΜɻ")
    return
    }
    // a Λ࢖͏ॲཧ

    View Slide

  72. // Simple domain error → Logic failure
    let number: Int = Int(string)!

    View Slide

  73. from \ to SDE RE UE LF
    SDE - guard let
    throw
    guard let
    fatalError
    !
    RE try? - do-catch
    fatalError
    try!
    UE -
    LF if/guard
    return nil
    if/guard
    throw
    if/guard
    fatalError
    -
    SDE: Simple domain error, RE: Recoverable error,
    UE: Universal error, LF: Logic failure

    View Slide

  74. // Ͳ͏ͤ ! ͢Δ͜ͱʹͳͬͯແବ
    func sort(_ ns: inout [Int]) {
    for i in 0 ... ns.count {
    for j in i + 1 ... ns.count {
    if ns[j]! < ns[i]! {
    let t = ns[j]!
    ns[j] = ns[i]!
    ns[i] = t
    }
    }
    }
    }

    View Slide

  75. ΫΠζλΠϜ

    View Slide

  76. ΫΠζͷϧʔϧ
    - ࡾ୒ܗࣜ
    - ੍ݶ࣌ؒ͸ 30 ඵ
    - શ෦Ͱ 5 ໰
    - ඞͣࡾ୒ͷͲΕ͔ʹखΛڍ͛Δ

    View Slide

  77. ΫΠζͷϧʔϧ
    - ࡾ୒ܗࣜ
    - ੍ݶ࣌ؒ͸ 30 ඵ
    - શ෦Ͱ 5 ໰
    - ඞͣࡾ୒ͷͲΕ͔ʹखΛڍ͛Δ

    View Slide

  78. ΫΠζͷϧʔϧ
    - ࡾ୒ܗࣜ
    - ੍ݶ࣌ؒ͸ 30 ඵ
    - શ෦Ͱ 5 ໰
    - ඞͣࡾ୒ͷͲΕ͔ʹखΛڍ͛Δ

    View Slide

  79. ΫΠζͷϧʔϧ
    - ࡾ୒ܗࣜ
    - ੍ݶ࣌ؒ͸ 30 ඵ
    - શ෦Ͱ 5 ໰
    - ඞͣࡾ୒ͷͲΕ͔ʹखΛڍ͛Δ

    View Slide

  80. @koher
    h"ps:/
    /twi"er.com/koher

    View Slide

  81. Q1. ϦόʔγͷϘʔυ

    View Slide

  82. let disk: Disk?
    = board[x, y]

    View Slide

  83. 1. Simple domain error
    struct Board {
    subscript(x: Int, y: Int) -> Disk? {
    guard (0..<8).contains(x) else { return nil }
    guard (0..<8).contains(y) else { return nil }
    ...
    }
    ...
    }

    View Slide

  84. 2. Universal error
    struct Board {
    subscript(x: Int, y: Int) -> Disk? {
    guard (0..<8).contains(x) else { fatalError() }
    guard (0..<8).contains(y) else { fatalError() }
    ...
    }
    ...
    }

    View Slide

  85. 3. Logic failure
    struct Board {
    subscript(x: Int, y: Int) -> Disk? {
    precondition((0..<8).contains(x))
    precondition((0..<8).contains(y))
    ...
    }
    ...
    }

    View Slide

  86. γϯΩϯάλΠϜ
    1. Simple domain error
    2. Universal error
    3. Logic failure

    View Slide

  87. ౴͑
    1. Simple domain error
    2. Universal error
    3. Logic failure

    View Slide

  88. | ○○○●|

    View Slide

  89. | ●○○○●|

    View Slide

  90. | ○○○ |

    View Slide

  91. | ●○○○ |

    View Slide

  92. | ○○○|

    View Slide

  93. | ●○○○|

    View Slide

  94. struct Board {
    subscript(x: Int, y: Int) -> Disk? {
    guard (0..<8).contains(x) else { return nil }
    guard (0..<8).contains(y) else { return nil }
    ...
    }
    ...
    }

    View Slide

  95. struct Board {
    subscript(x: Int, y: Int) -> Disk? {
    precondition((0..<8).contains(x))
    precondition((0..<8).contains(y))
    ...
    }
    ...
    }

    View Slide

  96. Q2. ΞϓϦʹόϯυϧ͞Εͨσʔλ

    View Slide

  97. let foo: Foo = loadFoo()

    View Slide

  98. 1. Recoverable error
    func loadFoo() throws -> Foo {
    guard let path = Bundle.main.path(forResource: "Foo", ofType: "json") else {
    throw ...
    }
    let url = URL(fileURLWithPath: path)
    let data = try Data(contentsOf: url)
    return try JSONDecoder().decode(Foo.self, from: data)
    }

    View Slide

  99. 2. Universal error
    func loadFoo() -> Foo {
    guard let path = Bundle.main.path(forResource: "Foo", ofType: "json") else {
    fatalError()
    }
    let url = URL(fileURLWithPath: path)
    do {
    let data = try Data(contentsOf: url)
    return try JSONDecoder().decode(Foo.self, from: data)
    } catch {
    fatalError()
    }
    }

    View Slide

  100. 3. Logic failure
    func loadFoo() -> Foo {
    let path = Bundle.main.path(forResource: "Foo", ofType: "json")!
    let url = URL(fileURLWithPath: path)
    let data = try! Data(contentsOf: url)
    return try! JSONDecoder().decode(Foo.self, from: data)
    }

    View Slide

  101. γϯΩϯάλΠϜ
    1. Recoverable error
    2. Universal error
    3. Logic failure

    View Slide

  102. ౴͑
    1. Recoverable error
    2. Universal error
    3. Logic failure

    View Slide

  103. guard let image = UIImage(named: "Foo") else {
    // ΤϥʔϋϯυϦϯά
    ...
    }
    // image Λ࢖͏ॲཧ

    View Slide

  104. let image = UIImage(named: "Foo")!
    // image Λ࢖͏ॲཧ

    View Slide

  105. Q3. ηϯαʔ͔Βͷσʔλऔಘ

    View Slide

  106. let foo: Foo = readFoo()

    View Slide

  107. 1. Recoverable error
    func readFoo() throws -> Foo {
    guard isFooSensorAvailable() else {
    throw ...
    }
    ...
    }

    View Slide

  108. 2. Universal error
    func readFoo() -> Foo {
    guard isFooSensorAvailable() else {
    fatalError()
    }
    ...
    }

    View Slide

  109. 3. Logic failure
    func readFoo() -> Foo {
    precondition(isFooSensorAvailable())
    ...
    }

    View Slide

  110. γϯΩϯάλΠϜ
    1. Recoverable error
    2. Universal error
    3. Logic failure

    View Slide

  111. ౴͑
    1. Recoverable error
    2. Universal error
    3. Logic failure

    View Slide

  112. Q4. ήʔϜͷηʔϒσʔλ

    View Slide

  113. let game: Game? =
    loadGame()

    View Slide

  114. 1. Recoverable error
    func loadGame() throws -> Game? {
    ...
    guard hash == savedHash else {
    throw ...
    }
    ...
    }

    View Slide

  115. 2. Universal error
    func loadGame() -> Game? {
    ...
    guard hash == savedHash else {
    fatalError()
    }
    ...
    }

    View Slide

  116. 3. Logic failure
    func loadGame() -> Game? {
    ...
    precondition(hash == savedHash)
    ...
    }

    View Slide

  117. γϯΩϯάλΠϜ
    1. Recoverable error
    2. Universal error
    3. Logic failure

    View Slide

  118. ౴͑
    1. Recoverable error
    2. Universal error
    3. Logic failure

    View Slide

  119. ౴͑
    1. Recoverable error
    2. Universal error
    3. Logic failure

    View Slide

  120. View Slide

  121. // ϥΠϒϥϦϨΠϠʔ
    func loadGame() -> Game? {
    ...
    }
    // ΞϓϦϨΠϠʔ
    func ... {
    guard let game = loadGame() else {
    fatalError()
    }
    // game Λ࢖͏ίʔυ
    }

    View Slide

  122. Q5. ը૾ͷੜ੒

    View Slide

  123. let image = Image(
    width: width,
    height: height,
    pixels: pixels)

    View Slide

  124. 1. Simple domain error
    struct Image {
    init?(width: Int, height: Int, pixels: [Pixel]) {
    guard width >= 0 else { return nil }
    guard height >= 0 else { return nil }
    guard pixels.count == width * height else { return nil }
    ...
    }
    }

    View Slide

  125. 2. Universal error
    struct Image {
    init(width: Int, height: Int, pixels: [Pixel]) {
    guard width >= 0 else { return fatalError() }
    guard height >= 0 else { return fatalError() }
    guard pixels.count == width * height else { return fatalError() }
    ...
    }
    }

    View Slide

  126. 3. Logic failure
    struct Image {
    init(width: Int, height: Int, pixels: [Pixel]) {
    precondition(width >= 0)
    precondition(height >= 0)
    precondition(pixels.count == width)
    ...
    }
    }

    View Slide

  127. γϯΩϯάλΠϜ
    1. Simple domain error
    2. Universal error
    3. Logic failure

    View Slide

  128. ౴͑
    1. Simple domain error
    2. Universal error
    3. Logic failure

    View Slide

  129. ౴͑
    1. Simple domain error
    2. Universal error
    3. Logic failure

    View Slide

  130. let a = [2, 3, 5]
    a.prefix(-1) // Logic failure

    View Slide

  131. print(3...2) // Logic failure

    View Slide