E07236: dynamic class with captured variables requires 'default operator ?' to define set/unset semantics for captured fields
What went wrong
Your dynamic class captures variables from its enclosing scope, and those captured variables become private fields on the generated class. Since the class now has fields, it must define its own '?' (isSet) operator to support EK9's tri-state semantics.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 93 (How do I define a class in EK9?)
Quick fix
Add 'default operator ?' among the dynamic class's operators (after its methods) for the generated behaviour, true only when EVERY captured field is set - good.ek9 in the [EXAMPLE] section below. Or write 'override operator ? as pure' yourself when only some captures matter - good_custom.ek9 below.
Why captures are fields
A dynamic class that captures a variable - '(prefix) trait of Printable as class' - is compiled to a class with a private field for each capture ('prefix' becomes a field of type String). Because the class now has a field, the '?' it inherits from Any cannot inspect it. You must define '?' so that guards, safe access, and coalescing work correctly.
Multiple captures
Each captured variable becomes a separate field, and the generated '?' checks every one of them: with captures (prefix, suffix, separator), 'default operator ?' is true only when prefix?, suffix? and separator? are all true.
Custom operator implementation
If 'every capture set' does not suit your needs, write the operator yourself. In good_custom.ek9 below the dynamic class captures a host, a port and a timeout, and its '?' requires only the host and the port: the timeout is optional.
[MULTI-TRAIT DELEGATION] With 'by' delegation the delegated variables are captures too, so they also become private fields and the dynamic class needs its '?' (good_delegation.ek9 below).
How to fix it
Add ONE of these among the dynamic class's operators, after its method overrides:
- 'default operator ?' - the compiler generates it from the captured fields.
- 'override operator ? as pure' with '<- rtn as Boolean:' and your own logic.
Use 'default' when "every captured field set = object set" is what you want. Use 'override' when you need custom logic (e.g., only required captures matter).
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E07236: dynamic class with captured variables requires 'default operator ?' to define set/unset semantics for captured fields
#!ek9 defines module error.e07236.bad defines trait Printable describe() as abstract <- result as String? Formatter format() as abstract -> items as List of String <- result as String? defines function testUnnamedCapture() prefix <- "Hello" //Single unnamed capture — prefix becomes a private field printer <- (prefix) trait of Printable as class override describe() <- result as String: prefix //Missing: default operator ? testNamedCapture() greeting <- "Hi" //Named capture — greeting becomes a private field printer <- Greeter(greeting) trait of Printable as class override describe() <- result as String: greeting //Missing: default operator ? testMultipleCaptures() prefix <- "[" suffix <- "]" //Multiple captures — both become private fields formatter <- (prefix, suffix) trait of Printable as class override describe() <- result as String: prefix + suffix //Missing: default operator ? testCaptureWithOperatorPresent() prefix <- "OK" //This is valid — default operator ? is defined printer <- (prefix) trait of Printable as class override describe() <- result as String: prefix default operator ? require printer? testNoCapturesNoError() //No captures — no fields — no ? required printer <- () trait of Printable as class override describe() <- result as String: "static" default operator ? require printer?
Fixed: Add 'default operator ?' to the dynamic class
#!ek9 defines module error.e07236.good defines trait Printable describe() as abstract <- result as String? defines program PrintGreeting() stdout <- Stdout() prefix <- "Hello" //The capture becomes a field, so the dynamic class says when it is set printer <- (prefix) trait of Printable as class override describe() <- result as String: prefix default operator ? stdout.println(printer.describe())
Fixed: With 'by' delegation the captures are fields too
#!ek9 defines module error.e07236.good.delegation defines trait LengthCheck longEnough() as abstract -> text as String <- rtn as Boolean? CharacterCheck allLetters() as abstract -> text as String <- rtn as Boolean? defines class MinimumLength with trait of LengthCheck override longEnough() -> text as String <- rtn as Boolean: not text.empty() Letters with trait of CharacterCheck override allLetters() -> text as String <- rtn as Boolean: text matches /^[a-zA-Z]+$/ defines program Validate() stdout <- Stdout() lengthCheck <- MinimumLength() characterCheck <- Letters() //Delegated 'by' captures: they are fields too, so '?' is defaulted validator <- (lengthCheck, characterCheck) trait of LengthCheck by lengthCheck, CharacterCheck by characterCheck default operator ? stdout.println($validator.longEnough("Steve"))
Fixed: Write the '?' yourself: only some captures are required
#!ek9 defines module error.e07236.good.custom defines trait Connectable connect() as abstract <- rtn as Boolean? defines program Connect() stdout <- Stdout() host <- "localhost" port <- 8080 timeout <- Integer() //'set' means the host and port are set; the timeout is optional connection <- (host, port, timeout) trait of Connectable as class override connect() <- rtn as Boolean: host? and port? and (timeout? or port > 0) override operator ? as pure <- rtn as Boolean: host? and port? ready <- connection? stdout.println($ready)
Questions and answers
These Q&A entries show E07236 and its fix: