Rich
Rich

Reputation: 8202

Generic type not identical to the same type

I have the following (I've simplified it to the most basic case):

class Something<H: Hashable> {

}

func function<H: NSDate>() -> Something<H> {
    let s: Something<NSDate> = Something()
    return s
}

The error is on the return s line:

NSDate is not identical to 'H'

But this doesn't make an sense as any subclass of NSDate or NSDate itself should be allowed by this.

For example the following works:

let dateSomething: Something<NSDate> = Something()
functionWorks(dateSomething)

func functionWorks<H: NSDate>(parameter: Something<H>) {

}

Does anyone have any ideas why the first example isn't working? I'm currently thinking it might be an issue with Swift itself...

Upvotes: 3

Views: 687

Answers (3)

Rob Napier
Rob Napier

Reputation: 299325

To get back to what you're asking for:

func function<H: NSDate>() -> Something<H> {

As Nate and rickster note, this won't work because of Swift's type rules. But it's also not really what you mean. There is no reason to use type parameterization to indicate one specific type. You don't need to say "H, where H is NSDate." You should just say "NSDate." What you really meant was:

func function() -> Something<NSDate> {

And that will work fine. In fact, because of type inference, it's even simpler:

func function() -> Something<NSDate> {
    return Something()
}

Upvotes: 5

rickster
rickster

Reputation: 126117

Generic type parameters don't unify. Type constraints are checked only when specializing a generic, and otherwise two thing<T> with different things inside the angle brackets are completely unrelated types, even if the things inside the angle brackets are themselves related types.

To put it another way: Swift generics are type preserving. If someone calls function<SubclassOfNSDate>(), it needs to return Something<SubclassOfNSDate>, not Something<NSDate>. To return the latter would erase the type the caller provided. (Some other languages do generics with type erasure, so you could do this there. But type erasure systems have other drawbacks, so Swift doesn't go that way.)

It's hard to see what you're really trying to accomplish here from what you've posted. Changing this line should at least make it compile, though:

let s: Something<H> = Something()

This way you're using the H (which happens to be NSDate) from the function's generic parameter (which is what you're expected to return).

Upvotes: 5

Nate Cook
Nate Cook

Reputation: 93276

It doesn't work because the particular subtype H for a call to your function could be an NSDate subclass:

// subclass NSDate
class SpecialDate : NSDate { }

// this needs a Something<SpecialDate> returned, not a Something<NSDate>
let specialSomething: Something<SpecialDate> = function()

The solution is to use H to subtype Something in your function:

func function<H: NSDate>() -> Something<H> {
    let s: Something<H> = Something()
    return s
}

Upvotes: 4

Related Questions