Weird generics error

I'm trying to implement following structure using generics. Getting a weird compiler error, can't figure out why.

class Translator<T:Hashable> {...}

class FooTranslator<String>:Translator<String> {...}

The idea is that Translator uses T as the type of a key in a dictionary. This can be e.g. a String or an enum. Subclass provides concrete dictionary.

But it fails because of this: "Type 'String' does not conform to protocol 'Hashable'"

But String conforms to Hashable! Am I nuts? It also doesn't work with Int, which also conforms to Hashable. It also doesn't work if I replace Hashable with Equatable, which should be also implemented by both.

If I remove the type constraint, just for testing (where I also have to disable the dictionary, as I can't use anything not hashable as key there) - it compiles

class Translator<T> {...}

class FooTranslator<String>:Translator<String> {...}

What am I doing wrong?

Jon Skeet
people
quotationmark

I'm not a Swift developer, but having seen similar problems in Java, I suspect the problem is that at the moment you're declaring a type parameter called String because you're declaring class FooTranslator<String> - so the type argument in Translator<String> is just that type parameter, which has no constraints. You don't want a type parameter at all, I suspect (i.e. you don't want your FooTranslator to be a generic class itself.)

As noted in comments, in Swift subclasses of a generic class also have to be generic. You could possibly declare a throw-away type parameter, like this:

class FooTranslator<T>:Translator<String>

which still avoids declaring a new type parameter called String, which was what was causing the problem. It means you're introducing a new type parameter when you don't want any type parameters, but it's possibly better than nothing...

This is all on the assumption that you really need a subclass, e.g. to add or override members. On the other hand, if you just want a type which is exactly the same as Translator<String>, you should use a type alias instead:

typealias FooTranslator = Translator<String>

Or even mix the two in a horrible way, if you genuinely want a subclass but don't want to have to refer to it in a generic way:

class GenericFooTranslator<T>:Translator<String>
typealias FooTranslator = GenericFooTranslator<Int>

(Note that the Int here is deliberately not String, to show that the T in Translator isn't the same as the T in FooTranslator.)

people

See more on this question at Stackoverflow