HomeiOS DevelopmentIncorrect specialised generic perform will get referred to as in Swift 3...

Incorrect specialised generic perform will get referred to as in Swift 3 from an oblique name


I’ve code that follows the overall design of:

protocol DispatchType {}
class DispatchType1: DispatchType {}
class DispatchType2: DispatchType {}

func doBar(worth:D) {
    print("normal perform referred to as")
}

func doBar(worth:DispatchType1) {
    print("DispatchType1 referred to as")
}

func doBar(worth:DispatchType2) {
    print("DispatchType2 referred to as")
}

the place in actuality DispatchType is definitely a backend storage. The doBarfeatures are optimized strategies that rely on the proper storage sort. The whole lot works tremendous if I do:

let d1 = DispatchType1()
let d2 = DispatchType2()

doBar(worth: d1)    // "DispatchType1 referred to as"
doBar(worth: d2)    // "DispatchType2 referred to as"

Nevertheless, if I make a perform that calls doBar:

func check(worth:D) {
    doBar(worth: worth)
}

and I strive an identical calling sample, I get:

check(worth: d1)     // "normal perform referred to as"
check(worth: d2)     // "normal perform referred to as"

This looks as if one thing that Swift ought to be capable to deal with because it ought to be capable to decide at compile time the sort constraints. Simply as a fast check, I additionally tried writing doBar as:

func doBar(worth:D) the place D:DispatchType1 {
    print("DispatchType1 referred to as")
}

func doBar(worth:D) the place D:DispatchType2 {
    print("DispatchType2 referred to as")
}

however get the identical outcomes.

Any concepts if that is right Swift habits, and if that’s the case, a great way to get round this habits?

Edit 1: Instance of why I used to be attempting to keep away from utilizing protocols. Suppose I’ve the code (vastly simplified from my precise code):

protocol Storage {
     // ...
}

class Tensor {
    // ...
}

For the Tensor class I’ve a base set of operations that may be carried out on the Tensors. Nevertheless, the operations themselves will change their habits primarily based on the storage. Presently I accomplish this with:

func dot(_ lhs:Tensor, _ rhs:Tensor) -> Tensor { ... }

Whereas I can put these within the Tensor class and use extensions:

extension Tensor the place S:CBlasStorage {
    func dot(_ tensor:Tensor) -> Tensor {
       // ...
    }
}

this has a number of uncomfortable side effects which I do not like:

  1. I believe dot(lhs, rhs) is preferable to lhs.dot(rhs). Comfort features may be written to get round this, however that may create an enormous explosion of code.

  2. This may trigger the Tensor class to turn out to be monolithic. I actually want having it include the minimal quantity of code mandatory and increase its performance by auxiliary features.

  3. Associated to (2), which means that anybody who desires so as to add new performance should contact the bottom class, which I think about unhealthy design.

Edit 2: One different is that issues work anticipated in the event you use constraints for every part:

func check(worth:D) the place D:DispatchType1 {
    doBar(worth: worth)
}

func check(worth:D) the place D:DispatchType2 {
    doBar(worth: worth)
}

will trigger the proper doBar to be referred to as. This additionally is not ideally suited, as it would trigger loads of further code to be written, however at the very least lets me maintain my present design.

Edit 3: I got here throughout documentation displaying using static key phrase with generics. This helps at the very least with level (1):

class Tensor {
   // ...
   static func cos(_ tensor:Tensor) -> Tensor {
       // ...
   }
}

lets you write:

let end result = Tensor.cos(worth)

and it helps operator overloading:

let end result = value1 + value2

it does have the added verbosity of required Tensor. This will made a bit of higher with:

typealias T = Tensor

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments