A.R.
A.R.

Reputation: 15695

Swift Generic Type conversion?

I am new to Swift, and I am trying to mess around with the generics a bit, but I am getting strange build errors that I don't understand. Here is the example code:

class CJunk
{
    var HowMuch:Int = 0
}

class CGarbage : CJunk
{

}

// This will not compile because:
// Cannot convert return expression of type 'CGarbage' to return type 'T'
func MakeGarbage<T:CJunk>(input:CJunk) -> T
{
    let x: CGarbage = CGarbage()
    x.HowMuch = input.HowMuch * 2;
    return x;
}

OK, that seems odd since CGargabe is a CJunk... Let's try something a little more basic:

// Cannot convert return expression of type 'CJunk' to return type 'T'
func MakeGarbage<T:CJunk>(input:CJunk) -> T
{
    let x: CJunk = CJunk()
    x.HowMuch = input.HowMuch * 2;
    return x;
}

EDIT: The problem is that in each case I am erroneously trying to upcast. This actually has nothing to do with generics, and more with OOP fundamentals. The other problem is that I misinterpreted the error message. Ooops.

Upvotes: 2

Views: 693

Answers (1)

luk2302
luk2302

Reputation: 57124

What MartinR already mentioned a bit more clearly stated:

<T:CJunk> means that T is one very specific subclass of CJunk. Since you try to return CGarbage or CJunk there is no guarantee whatsoever that that returned class actually matches the specific T - it may not be convertable.

Your example is so simply that generics is simply overkill and the easy solution is to drop them altogether since your function returns the same type all the time any way:

func MakeGarbage(input:CJunk) -> CGarbage {
    let x: CGarbage = CGarbage()
    x.HowMuch = input.HowMuch * 2;
    return x;
}

We will be happy to help with more complex generics problems - this one is so basic that it simply does not make any sense at all to use generics at all.

If you think about your generic Method the compiler has to somehow infer the type T or you have to specify the type. The compiler cannot infer it in the first place, if you would get over the initial compiler error. Therefore you as the developer would have to provide the type of T explicitly. When you do that and specify that T has to actually be YourSecondSubclass then it is easy to see why the compiler complains in the first place, because now your method will return a CGarbage which is clearly not convertable to YourSecondSubclass. I hope that explains it a bit!?

Consider the following

class CJunk { var HowMuch:Int = 0 }
class CGarbage : CJunk { }
class MoreGarbage : CJunk { }

func MakeGarbage<T:CJunk>(input:CJunk) -> T {
    let x: CGarbage = CGarbage()
    x.HowMuch = input.HowMuch * 2;
    return x;
}

var more : MoreGarbage = MakeGarbage(CJunk())

The compiler no goes ahead and infers T to be MoreGarbage since that is the expected return type, no unfortunately the actual returned type CGarbage has nothing to do with MoreGarbage.

This argument works for both cases exactly the same: the compiler infers the type of T from the caller and there is no guarantee that the you can convert CJunk to T.

Upvotes: 1

Related Questions