I’m having trouble using Swift generics for the first time; specifically in regard to writing type annotations for my generic types.
Essentially, I’m using a generic parent class for different materials in a game. My intent is to be able to use the parent class’ type annotation for function parameters and returns, but mentioning the parent class requires that I pass generic constraints that refer to one of the child types, which ultimately limits the usage of the generic to a single type. Here’s my example.
Note: I realize that I can use existential types in-place of generics, but I’m trying to allow Swift to use static dispatch, in the interest of performance.
Import Foundation
Class MaterialExample<T: MaterialSubtype> {
let subtype: T
init(subtype: T) {
self.subtype = subtype
}//init
/*represents one of the child types, which will have it’s own nested type that conforms to MaterialSubtype*/
enum PrimaryType: String, RawRepresentable {
case metal
}
}//MaterialExample
/* Each child type has its own implementation of
Protocol MaterialSubtype that refers to its own uses. So, the child types pass their implementation of Subtype when their inheritance is declared.
Ultimately, I just use this protocol to enforce type safety in the hierarchy.*/
Protocol MaterialSubtype: RawRepresentable where RawValue: StringProtocol {}
Class Metal: MaterialExample<Subtype> {
Enum Subtype: MaterialSubtype {
Case bar
}//Subtype
}//Metal
Class Glass: Material<Subtype> {
Enum Subtype: MaterialSubtype {
Case pane
}//Subtype
}//Glass
Where I’m having issues is when trying to use the MaterialExample class is when I need to pass a MaterialExample object as a function parameter, or declare it as a return type for a function. When doing so, I’m required to reference its generic parameters, which ultimately eliminates its generic capabilities when used outside of itself:
These cause errors, but would retain MaterialExample’s generic flexibility:
Let genericMaterial: MaterialExample
Func someFunc(material: MaterialExample) {}
Func makeSomeMaterial() -> MaterialExample {
//some return statement
}
Because of this, I’m required to write those same lines like this, limiting MaterialExample to one of its child classes:
Let genericMaterial: MaterialExample<Glass.Subtype>
Func someFunc(material: MaterialExample<Metal.Subtype>) {}
Func makeSomeMaterial() -> MaterialExample<Glass.Subtype> {
// some turn call
}
I want my type annotations for properties and methods to be as flexible as the MaterialExample class is intended to be, but the lack of ability to do so is making me feel like I’m missing something. Is there a way to accomplish my intent without using existential types?