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

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

Yuta Koshizawa
September 16, 2017
6.3k

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

Yuta Koshizawa

September 16, 2017
Tweet

More Decks by Yuta Koshizawa

Transcript

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

    View full-size slide

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

    View full-size slide

  3. throw FooError()

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  6. fatalError()

    View full-size slide

  7. precondition(...)

    View full-size slide

  8. assertionFailure()

    View full-size slide

  9. preconditionFailure()

    View full-size slide

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

    View full-size slide

  11. func foo() { foo() }

    View full-size slide

  12. 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 full-size slide

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

    View full-size slide

  14. 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 full-size slide

  15. Simple domain errors
    Recoverable errors
    Universal errors
    Logic failures

    View full-size slide

  16. Simple domain errors

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  19. let element: Int? =
    array.first

    View full-size slide

  20. let value =
    dictionary["unknownKey"]

    View full-size slide

  21. Recoverable errors

    View full-size slide

  22. try fileManager
    .removeItem(at: url)

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  26. Universal errors

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  29. func foo() { foo() }

    View full-size slide

  30. thread.cancel()

    View full-size slide

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

    View full-size slide

  32. Logic failures

    View full-size slide

  33. 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 full-size slide

  34. 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 full-size slide

  35. 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 full-size slide

  36. 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 full-size slide

  37. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  40. 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 full-size slide

  41. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

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

    View full-size slide

  49. 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 full-size slide

  50. Simple domain errors
    Recoverable errors
    Universal errors
    Logic failures

    View full-size slide

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

    View full-size slide

  52. // 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  55. 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 full-size slide

  56. // Ͳ͏ͤ ! ͢Δ͜ͱʹͳͬͯແବ
    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 full-size slide

  57. ΫΠζλΠϜ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  65. 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 full-size slide

  66. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  70. | ○○○●|

    View full-size slide

  71. | ●○○○●|

    View full-size slide

  72. | ○○○ |

    View full-size slide

  73. | ●○○○ |

    View full-size slide

  74. | ○○○|

    View full-size slide

  75. | ●○○○|

    View full-size slide

  76. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  79. let foo: Foo = loadFoo()

    View full-size slide

  80. 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 full-size slide

  81. 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 full-size slide

  82. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  88. let foo: Foo = readFoo()

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  95. let game: Game? =
    loadGame()

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  103. Q5. ը૾ͷੜ੒

    View full-size slide

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

    View full-size slide

  105. 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 full-size slide

  106. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide