How do I extend or specialize a generic type in EK9?

← Generics · Ref: Q197

EK9 allows extending generic types that are marked 'as open'. You create concrete specializations by providing specific type arguments.

OPEN GENERIC TYPES

Mark a generic type as open to allow extension:

  BaseList of type T as open
    items as List of T?

SPECIALIZATION VIA EXTENSION

Create a concrete type by extending with specific types:

  NameList is BaseList of String

NameList is now a concrete class with String-typed items.

ADDING METHODS

Specializations can add new methods:

  NameList is BaseList of String
    findByPrefix()
      -> prefix as String
      <- rtn as String?

GENERIC FUNCTION INSTANTIATION

Generic functions use 'is' or 'extends' for instantiation:

  intCompare <- () is compareFunc of Integer as function

See Q194 for generic classes. See Q101 for closed by default. See Q102 for as open. See Q58 for generic functions.

Example

#!ek9
defines module qa.generics.extending

  defines function

    compareFunc() of type T as open
      ->
        item1 as T
        item2 as T
      <-
        rtn as Integer := item1 <=> item2

  defines class

    BaseList of type T as open
      items as List of T?

      BaseList()
        items :=? List() of T

      BaseList()
        -> item as T
        items: List() of T
        items += item

      addItem()
        -> item as T
        if not items?
          items: List() of T
        items += item

      count() as pure
        <- rtn as Integer: 0
        if items?
          rtn: length items

      default operator ?

    // Specialization: concrete type from generic
    NameList is BaseList of String

      default operator ?

  defines program

    ExtendingGenericsDemo()
      stdout <- Stdout()

      // === GENERIC FUNCTION INSTANTIATION ===

      intCompare <- () is compareFunc of Integer as function
      result <- intCompare(10, 20)
      stdout.println(`Compare 10 vs 20: ${result}`)

      strCompare <- () extends compareFunc of String as function
      strResult <- strCompare("apple", "banana")
      stdout.println(`Compare apple vs banana: ${strResult}`)

      // === SPECIALIZED CLASS ===

      names <- NameList()
      names.addItem("Alice")
      names.addItem("Bob")
      stdout.println(`Name count: ${names.count()}`)

Common mistakes

E50020 — Generic functions must be instantiated with 'as function', not 'as class'. Using the wrong construct type triggers E50020 - incompatible genus (the generic is a function, not a class). See ek9 -h E50020 for details.

Incorrect:

intCompare <- () is compareFunc of Integer as class

Correct:

intCompare <- () is compareFunc of Integer as function
Other ways to ask this
  • How do I create a concrete type from a generic in EK9?
  • Can I extend a parameterized type in EK9?
  • How does generic specialization work in EK9?

Coming from another language?

Java: class NameList extends ArrayList<String>. C++: template specialization or typedef. Rust: type alias or newtype pattern. Go: type NameList = List[string] (no true specialization). Kotlin: class NameList : ArrayList<String>(). EK9: 'NameList is BaseList of String' with optional additional methods.

Keywords: concrete, extend, generic, inherit, open, parameterize, parameterized, specialize, type, type-parameter