Write me a generic Formatter of type T that captures a prefix variable from the enclosing scope and uses it inside the overridden format method.

← Generics · Ref: Q1235

Dynamic classes that extend a generic type can ALSO capture variables from the enclosing scope. The captured variables are listed in the parentheses before 'extends', and become fields on the dynamic class. They can be used inside the overridden methods alongside the type-substituted parameters.

GENERIC ABSTRACT FORMATTER

  Formatter of type T as abstract
    format() as abstract
      -> arg0 as T
      <- rtn as String?
    override operator ? as pure
      <- rtn as Boolean: true

DYNAMIC CLASS WITH CAPTURE

  prefix <- "Item"
  formatter <- (prefix) extends Formatter of Integer as class
    override format()
      -> arg0 as Integer
      <- rtn as String: `${prefix}: ${$arg0}`
    default operator ?

The parentheses '(prefix)' declare which outer variables to capture. They become fields on the anonymous class and are visible inside the overridden methods. The generic type parameter T is replaced by Integer at the same time.

USAGE

  stdout.println(formatter.format(42))

This combines TWO features in one expression: generic type extension AND closure-style capture. The captured prefix coexists with the substituted Integer parameter.

See Q1234 for basic generic extension without capture. See Q601 for dynamic functions with capture. See Q197 for extending generics.

Example

defines module qa.genericsdeep.formattercapture

  defines class

    Formatter of type T as abstract

      format() as abstract
        -> arg0 as T
        <- rtn as String?

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

  defines program

    FormatterCaptureDemo()
      stdout <- Stdout()
      prefix <- "Item"

      formatter <- (prefix) extends Formatter of Integer as class
        override format()
          -> arg0 as Integer
          <- rtn as String: `${prefix}: ${$arg0}`
        default operator ?

      stdout.println(formatter.format(42))

Common mistakes

E50001 — If you reference an outer-scope variable inside the dynamic class body but do not list it in the capture parentheses, the variable is not resolved (E50001) because it is never brought into the dynamic class's scope. List it in the capture parentheses, e.g. (prefix), to make it available. See ek9 -h E50001 for details.

Incorrect:

() extends Formatter of Integer as class

Correct:

(prefix) extends Formatter of Integer as class
Other ways to ask this
  • Create a dynamic class extending a generic type that captures a local variable.
  • Show me how generic dynamic classes combine with variable capture in EK9.
  • Implement a parameterised Formatter that captures a prefix and formats Integer values.
  • Build a generic formatter dynamic class that uses an outer-scope variable.

Coming from another language?

Java: anonymous inner class capturing effectively-final outer variables. Kotlin: object expression with closure over outer scope. Scala: anonymous subclass with closure. JavaScript: class extending a generic-like base that closes over outer variables. EK9: explicit '(capturedVar)' syntax makes capture intentional and visible.

Keywords: dynamic class, capture, of type, anonymous, closure, inline, extends, generic