Why cannot I use named dynamic classes inside a generic type definition?

← Generics · Ref: Q648

EK9 does not allow named dynamic classes inside generic type or function definitions. Dynamic classes created inside generics must be anonymous (unnamed).

PROHIBITED PATTERN

Inside a generic body, you cannot define a named dynamic class because the name would need to be monomorphised for each type instantiation, creating ambiguous class identities.

CORRECT PATTERN

Use anonymous dynamic classes with traits:

  handler <- () with trait of EventHandler as class
    override handle()
      <- rtn as Boolean: true

No name means no monomorphisation conflict.

ALTERNATIVE: DEFINE OUTSIDE

Define the class outside the generic, then use it inside:

  ConcreteHandler with trait of EventHandler
    ...

Then reference ConcreteHandler from within the generic body.

See Q647 for function constraint limits. See Q646 for type inference limits. See Q194 for generic class basics.

Example

defines module qa.genericsdeep.nonameddynamic

  defines trait

    <?-
      Trait used as contract for dynamic classes.
    -?>
    Renderable
      render() as pure abstract
        <- rtn as String?

  defines class

    <?-
      Named class defined OUTSIDE the generic (correct approach).
      Can be referenced from inside generic bodies.
    -?>
    TextRenderer with trait of Renderable
      content as String?

      default private TextRenderer() as pure

      TextRenderer() as pure
        -> txt as String
        content :=? String(txt)

      override render() as pure
        <- rtn as String: String(content)

      override operator ? as pure
        <- rtn as Boolean: content?

    <?-
      Generic class that uses the trait, not named dynamic classes.
    -?>
    Displayer of type T constrain by Renderable
      item as T?

      default private Displayer() as pure

      Displayer() as pure
        -> inputItem as T
        item :=? inputItem

      show()
        <- rtn as String: "empty"
        if item?
          rtn: item.render()

      default operator ?

  defines program

    NoDynamicInGenericDemo()
      stdout <- Stdout()

      renderer <- TextRenderer("EK9 generics")
      displayer <- Displayer(renderer)
      output <- displayer.show()
      stdout.println(`Display: ${output}`)

Common mistakes

E06090 — Named dynamic classes like 'MyRenderer' are not allowed inside generic type definitions. The generic body is monomorphised for each type parameter, so a named class would be created multiple times. Use anonymous dynamic classes instead. See ek9 -h E06090 for details.

Incorrect:

named as Renderable: MyRenderer() with trait of Renderable as class
          override render()
            <- rtn as String: "dynamic"

Correct:

if item?
          rtn: item.render()
Other ways to ask this
  • What is E06090 named dynamic class in generic?
  • Can I create dynamic classes inside a generic class body?
  • Why are named dynamic classes prohibited in generic definitions?

Coming from another language?

Java: anonymous inner classes freely used inside generics. C++: lambdas and local classes inside templates. Rust: closures inside generic functions. Go: anonymous structs (limited). Kotlin: anonymous objects inside generics. EK9: named dynamic classes prohibited in generic bodies, use anonymous or define outside.

Keywords: named, capture, monomorphisation, anonymous, type-parameter, generic, class, prohibited, E06090, dynamic, closure