What is the correct syntax for generic type parameterization and instantiation?

← Generics · Ref: Q681

EK9 uses 'of type T' syntax for declaring generic type parameters and 'of TypeName' for instantiating them. Correct usage requires matching the number of type parameters.

DECLARATION SYNTAX

Generic type parameters use 'of type':

  Container of type T
  Mapping of type (K, V)

The parameter names become placeholders for concrete types.

INSTANTIATION SYNTAX

Concrete types replace parameters with 'of':

  Container of String
  Mapping of (String, Integer)

The number of concrete types must match the declared parameters.

MISSING PARAMETERS (E06220)

Omitting required type parameters triggers E06220:

  container <- Container()          // Needs type unless inferred from args
  container <- Container() of String // Correct: explicit type

INFERRENCE FROM ARGUMENTS

When constructor arguments match type parameters, inference works:

  container <- Container("hello")   // T inferred as String

See Q642 for constructor inference. See Q654 for parameter count validation. See Q656 for argument count validation.

Example

defines module qa.genericsdeep.parameterizationsyntax

  defines class

    <?-
      Single type parameter generic.
      Demonstrates correct 'of type T' declaration syntax.
    -?>
    Holder of type T
      content as T?

      Holder() as pure
        content :=? T()

      Holder() as pure
        -> initialContent as T
        content :=? initialContent

      getContent()
        <- rtn as T: T()
        rtn :=? T(content)

      hasContent() as pure
        <- rtn as Boolean: content?

      default operator ?

    <?-
      Multi-parameter generic.
      Both parameters must be specified at instantiation.
    -?>
    Pair of type (A, B)
      first as A?
      second as B?

      Pair() as pure
        first :=? A()
        second :=? B()

      Pair() as pure
        ->
          first as A
          second as B
        this.first :=? first
        this.second :=? second

      getFirst()
        <- rtn as A: A()
        rtn :=? A(first)

      getSecond()
        <- rtn as B: B()
        rtn :=? B(second)

      default operator ?

  defines program

    GenericParameterizationDemo()
      stdout <- Stdout()

      //Inference from single argument
      intHolder <- Holder(42)
      stdout.println(`Integer holder set: ${intHolder?}`)

      //Type declaration (no parentheses on lhs)
      typedHolder as Holder of String: Holder("typed")
      stdout.println(`Typed holder: ${typedHolder?}`)

      //Explicit type parameter (parentheses required for constructor)
      emptyHolder <- Holder() of String
      stdout.println(`Empty holder set: ${emptyHolder?}`)

      //Inference from multiple arguments
      entry <- Pair("key", 100)
      stdout.println(`Pair set: ${entry?}`)

      //Explicit multi-parameter
      emptyPair <- Pair() of (Float, Boolean)
      stdout.println(`Empty pair set: ${emptyPair?}`)

Common mistakes

E50060 — Holder has no toString() method. Use the $ prefix operator or ? for boolean check. See ek9 -h E50060 for details.

Incorrect:

stdout.println(intHolder.toString())

Correct:

stdout.println(`Integer holder set: ${intHolder?}`)

E06010 — Generic type instantiation must follow the correct syntax. Using incorrect call syntax when creating a parameterised type triggers E06010. See ek9 -h E06010 for details.

Incorrect:

intHolder <- Holder()(42)

Correct:

intHolder <- Holder(42)

E06010 — When no constructor arguments allow type inference, the type parameter must be explicitly specified. Omitting it triggers E06010 because the compiler cannot determine T. See ek9 -h E06010 for details.

Incorrect:

emptyHolder <- Holder()

Correct:

emptyHolder <- Holder() of String

E06200 — Parentheses are not allowed in type declarations on the left-hand side. Use 'Holder of String' not 'Holder() of String' for type references. See ek9 -h E06200 for details.

Incorrect:

      typedHolder as Holder() of String: Holder("typed")

Correct:

      typedHolder as Holder of String: Holder("typed")

E06210 — Parentheses are required when constructing a generic type. Use 'Holder() of String' not 'Holder of String' for constructors. See ek9 -h E06210 for details.

Incorrect:

      emptyHolder <- Holder of String

Correct:

      emptyHolder <- Holder() of String
Other ways to ask this
  • What is E06200 generic type reference error?
  • What is E06210 generic type instantiation error?
  • What is E06220 missing generic type parameter?
  • How do I correctly reference and create generic types?

Coming from another language?

Java: angle brackets List<String>. Rust: turbofish Vec::<String>. Go: brackets List[String]. Python: hints List[str]. EK9: 'of' syntax - List of String, Dict of (String, Integer).

Keywords: of, syntax, parameterization, E06200, E06220, type, generic, instantiation, type-parameter, E06210