Konrad Nowicki
Konrad Nowicki

Reputation: 1929

Swift generic function does not compile in testing

I have a problem with compiling tests cases in Swift. It looks like the compiler is loosing information about template type but other generic methods are working fine. What am I missing?

public class MatchNorm {

    public static func resolve1<T:SequenceType where T.Generator.Element:MatchNormElement>(list: T, lti: LinearTransformation, accuracy: Double) -> LinearTransformation {
        // no problem
        return MatchNorm.resolve1(list, lti: lti, accuracy: accuracy)
    }

    public static func resolve2<T:SequenceType where T.Generator.Element:MatchNormElement>(list: T, lti: LinearTransformation, accuracy: Double) -> LinearTransformation {

        for elem in list {
            print(elem.x)
        }
        return lti
    }
}
public class MatchNormTest: XCTestCase  {
    func testMatchNorm1() {
        var list = [MatchNormElement]()

        // compilation error here!
        let  ll = MatchNorm.resolve1(list, lti: LinearTransformation(1), accuracy: 0.001)
// MatchNormTest.swift:70:29: Cannot invoke 'resolve1' with an argument list of type '([MatchNormElement], lti: LinearTransformation, accuracy: Double)'
// MatchNormTest.swift:70:29: Expected an argument list of type '(T, lti: LinearTransformation, accuracy: Double)'
    }
}

Update

MatchNormElement is a protocol, so I changed it to concrete type. Now it works.

func testMatchNorm1() {
    var list = [Measurment]()

        // works fine
     let  ll = MatchNorm.resolve1(list, lti: LinearTransformation(1), accuracy: 0.001)
}

Upvotes: 0

Views: 191

Answers (1)

kandelvijaya
kandelvijaya

Reputation: 1585

This is reasonable for the compiler. Swift allows type conversion for a Concrete type to a Protocol based variable assignment.

However, Swift doesnot allow converting a set of Concrete Types to a set/array of Protocol by converting each. This is reasonable because of the following reasons:

Let suppose we have this constructs in place:

protocol IntType {}
extension Int: IntType{}

Now lets do the obvious thing:

let item = 12
let item2:IntType = item

Then the one that will look obvious to the eye: This wont compile for good reason.

let a = [1,2,3]
let b: [IntType] = a

Lets inspect the size of each Type before moving ahead:

sizeofValue(item)   //8
sizeofValue(item2)  //40

An array is a contagious memory of 8 bytes. So is Array a contagious memory of 40 bytes.

When we did this:

let b: [IntType] = a

We essentially tell the compiler to convert 8 bytes of array into 40 bytes of array and store it. Now as the array is contagious it has to destruct or reshuffle which is expensive task to do so. This hinders the performance and obviously you lose the type safety.

The compiler could this this transformation but Swift team decided for good reason that the user need to be explicit if they want this type transformation for 2 reasons: Performance and Type Safety.

Upvotes: 1

Related Questions