Generic Classes

In Generic Interfaces, we have learned the definition and usage of generic interfaces. In this section, we will delve into the definition and usage of generic classes.

The type of the Node key-value pair in the Map type can be defined using a generic class:

public open class Node<K, V> where K <: Hashable & Equatable<K> {
    public var key: Option<K> = Option<K>.None
    public var value: Option<V> = Option<V>.None

    public init() {}

    public init(key: K, value: V) {
        this.key = Option<K>.Some(key)
        this.value = Option<V>.Some(value)
    }
}

Because the key and value types may be different, Node requires two type parameters: K and V. For a map to work, it must be possible to test a pair of key values for equality, and for it to work fast it must also be possible to obtain a hash sum of a key value. Enforcing those requirements is the where K <: Hashable & Equatable<K> constraint placed on the key type, which indicates that a valid type argument for K must implement the Hashable and Equatable<K> interfaces. For details about generic constraints, see Generic Constraints.

The static member variables of a generic class share the same memory. Therefore, the type declarations and expressions of static member variables or properties cannot reference type parameters or contain uninstantiated generic type expressions. In addition, static variable or property initialization expressions cannot call static member functions or properties of a generic class.

class A<T> {}
class B<T> {
    static func foo() {1}
    static var err1: A<T> = A<T>() // Error, static member cannot depend on generic parameter 'Generics-T'
    static prop err2: A<T> { // Error, static member cannot depend on generic parameter 'Generics-T'
        get() {
            A<T>() // Error, static member cannot depend on generic parameter 'Generics-T'
        }
    }
    static var vfoo = foo() // Error, it's equal to 'static var vfoo = B<T>.foo()', implicit reference to generic 'T'.
    static var ok: Int64 = 1
}

main() {
    B<Int32>.ok = 2
    println(B<Int64>.ok) // 2
}