Slide 1

Slide 1 text

! Tagged potatotips #50 2018/04/19 @to4iki 1

Slide 2

Slide 2 text

Me • Takezawa Toshiki • @to4iki • iOS Engineer • builderscon • ! ☕ ♨ 2

Slide 3

Slide 3 text

IdΛܕԽ͍ͨ͠ (user.id ͱ subscription.idΛ۠ผ) 3

Slide 4

Slide 4 text

ex. 1 struct User: Decodable { typealias Id = String let id: Id let subscriptionId: Subscription.Id } struct Subscription: Decodable { typealias Id = String let id: Id } 4

Slide 5

Slide 5 text

! not type-safety // typealias User.Id = String func fetchUser(with id: User.Id) -> User? fetchUser(with: user.id) // OK fetchUser(with: user.subscriptionId) // OK fetchUser(with: "123") // OK 5

Slide 6

Slide 6 text

! type-safety struct User: Decodable { struct Id: Decodable { let value: String } ... } func fetchUser(with id: User.Id) -> User? fetchUser(with: user.id) // OK fetchUser(with: user.subscriptionId) // Compile Error fetchUser(with: "123") // Compile Error 6

Slide 7

Slide 7 text

ex. 2 { "id": "abc", "subscriptionId": "123" } // decode to `User` let decoder = JSONDecoder() let user = try! decoder.decode(User.self, from: Data(json.utf8)) 7

Slide 8

Slide 8 text

! DecodingError.typeMismatch at User.Id Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.Dictionary, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "id", intValue: nil)], debugDescription: ... 8

Slide 9

Slide 9 text

! DecodableΛ໌ࣔతʹ࣮૷͢Δ struct User: Decodable { struct Id: Decodable { let value: String init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() self.value = try container.decode(String.self) } } ... } 9

Slide 10

Slide 10 text

΋ͬͱεϚʔτʹղܾͰ͖ͳ͍͔ͳ 10

Slide 11

Slide 11 text

SE-0143: Conditional Conformance1 /// Swift4 /// Returns `true` if these arrays contain the same elements. public func ==(lhs: [Element], rhs: [Element]) -> Bool where Element : Equatable /// Swift4.1 extension Array: Equatable where Element: Equatable { static func ==(lhs: Array, rhs: Array) -> Bool } [1,2,3] == [1,2,3] // ok 1 https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md 11

Slide 12

Slide 12 text

Conditional2 Arrayʹ͓͍ͯɺElement͕Equatableͳ৔߹ʹݶΓ Conformance Array΋Equatableద߹͢Δ 2 આ໌্ͷҰྫͰ͢ 12

Slide 13

Slide 13 text

Tagged https://github.com/pointfreeco/swift-tagged 13

Slide 14

Slide 14 text

use Tagged struct User: Decodable, Equatable... { typealias Id = Tagged let id: Id let subscriptionId: Subscription.Id } struct Subscription: Decodable, Equatable... { typealias Id = Tagged let id: Id } 14

Slide 15

Slide 15 text

use Tagged "Decodable" let decoder = JSONDecoder() let user = try! decoder.decode(User.self, from: Data(json.utf8)) "Equatable" user1 == user2 // OK 15

Slide 16

Slide 16 text

https://github.com/pointfreeco/swift-tagged/blob/master/Sources/Tagged/Tagged.swift public struct Tagged { public var rawValue: RawValue public init(rawValue: RawValue) { self.rawValue = rawValue } } extension Tagged: RawRepresentable { } 16

Slide 17

Slide 17 text

https://github.com/pointfreeco/swift-tagged/blob/master/Sources/Tagged/Tagged.swift extension Tagged: Comparable where RawValue: Comparable { extension Tagged: Decodable where RawValue: Decodable { extension Tagged: Encodable where RawValue: Encodable { extension Tagged: Hashable where RawValue: Hashable { extension Tagged: Numeric where RawValue: Numeric { extension Tagged: ExpressibleByStringLiteral where RawValue: ExpressibleByStringLiteral { ... 17

Slide 18

Slide 18 text

Conclusion • Swift 4.1 Conditional Conformance ʹΑΓܕͷදݱྗ͕๛ ͔ʹͳͬͨ • Tagged Λ࢖͏͜ͱͰϓϦϛςΟϒ3ͳܕΛ؆୯ʹܕԽ͢Δ͜ ͱ͕Ͱ͖Δ 3 ೚ҙͷܕͰߏΘͳ͍͕ຊεϥΠυͷྫʹԊͬͯ͜ͷΑ͏ʹදݱ͍ͯ͠Δ 18

Slide 19

Slide 19 text

SeeAlso • Swift 4.1ͷConditional ConformanceͱδΣωϦΫεͷະདྷ • https://twitter.com/koher/status/985127876507860993 • Conditional Conformance in the Standard Library • https://swift.org/blog/conditional-conformance/ 19

Slide 20

Slide 20 text

Thanks 20