[swift-users] Refining generics in classes

Itai Ferber iferber at apple.com
Thu Nov 16 12:42:49 CST 2017


Hi Jon,

To clarify for those wondering, this is happening because the 
`doAThing()` method dispatches statically to `doSomething()` based on 
`NetworkRequests`’s `T`; since `doAThing()` isn’t overridden in 
`CompressedNetworkRequest`, the method is inherited directly, including 
that static dispatch.
To pull this example out a bit:

```swift
protocol X {}
protocol Y : X {}

class Foo<T : X> {
     var value: T

     init(value: T) {
         self.value = value
     }

     func doSomething() {
         doThing(value)
     }
}

class Bar<T : Y> : Foo<T> {}

func doThing<T : X>(_ v: T) { print("doThing<T : X>()") }
func doThing<T : Y>(_ v: T) { print("doThing<T : Y>()") }

extension Int : Y {}
Foo(value: 42).doSomething() // doThing<T : X>
Bar(value: 42).doSomething() // doThing<T : X>
```

In order to not inherit that static dispatch, `doSomething` needs to be 
overridden in `Bar`, even if to call the same function:

```swift
// …

class Bar<T : Y> : Foo<T> {
     override func doSomething() {
         doThing(value) // statically dispatches based on T : Y
     }
}

// …

Foo(value: 42).doSomething() // doThing<T : X>()
Bar(value: 42).doSomething() // doThing<T : Y>()
```

Unfortunately, I don’t think there’s a great way around this, short 
of duplicating the calls which do that sort of dispatch.
If you can somehow funnel some of these calls through one call site, it 
might make your life a bit easier.

— Itai

On 15 Nov 2017, at 20:42, Jon Shier via swift-users wrote:

> 	Swift Users:
> 	I have a generics use case which has somewhat stumped me. I have two 
> related protocols, JSONDecodable and CompressedDecodable, and 
> CompressedDecodable inherits from JSONDecodable (though that 
> relationship isn’t strictly necessary). I also have a generic 
> function that’s overloaded for each of those protocols. I’m trying 
> to write a class to make a network request expecting a generic 
> response type of either JSONDecodable or CompressedDecodable. However, 
> it doesn’t seem possible to write it in such a way that the overload 
> I need is called. Instead, it’s always the superclass’ type’s 
> overload that is called. For example:
>
> protocol JSONDecodable { init() }
> protocol CompressedDecodable: JSONDecodable { }
>
> class NetworkRequest<T: JSONDecodable> {
>
>     var response: T?
>
>     func doAThing() {
>         response = doSomething()
>     }
> }
>
> class CompressedNetworkRequest<U: CompressedDecodable>: 
> NetworkRequest<U> {
>
> }
>
> func doSomething<T: JSONDecodable>() -> T {
>     print("One: \(T.self)")
>     return T()
> }
>
> func doSomething<T: CompressedDecodable>() -> T {
>     print("Two: \(T.self)")
>     return T()
> }
>
> struct Uno: JSONDecodable { }
> struct Dos: CompressedDecodable { }
>
> NetworkRequest<Uno>().doAThing()
> CompressedNetworkRequest<Dos>().doAThing()
>
> In a playground this prints:
>
> One: Uno
> One: Dos
>
> Ultimately, I understand why this happens (NetworkRequest’s generic 
> type is always going to be JSONDecodable, no matter if it’s actually 
> a subtype). Is there any way, aside from completely duplicating the 
> class, to call the overload appropriate for the type passed in a class 
> like this?
>
>
>
> Jon Shier
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20171116/b265c88e/attachment.html>


More information about the swift-users mailing list