Why can't I use 'default operator <=>' on a record with a function delegate field?
← Classes and OOP · Ref: Q834
EK9 prevents 'default operator <=>' (and similar auto-generated comparison operators) on records that contain function delegate fields. The reason: how do you meaningfully compare two function references? Reference equality is almost never useful.
THE PROBLEM
When you write 'default operator <=>' the compiler auto-generates comparison by comparing each field. For String or Integer fields this is clear. But for a function delegate field, what does 'delegate1 <=> delegate2' mean? There is no meaningful default comparison.
WHAT STILL WORKS
- 'default operator ?' (isSet) — always valid, checks if the delegate is assigned
- Explicit operator implementation — you can write your own <=> that ignores the delegate, with a hand-written #? hashing the same fields
- Records without delegate fields — all default operators work normally
THIS EXAMPLE
Class EventHandler wraps a function delegate with an explicit comparator. SimpleRecord (no delegates) uses all default operators freely.
See Q116 for default operators. See Q96 for operator overview. See Q98 for record operators.
Example
#!ek9 defines module qa.classesandoop.delegate.defaultoperator defines function <?- Abstract function type used as a delegate. -?> Handler as abstract -> event as String <- rtn as Boolean? LogHandler() is Handler -> event as String <- rtn as Boolean: event? defines class <?- Class wrapping a function delegate field. Uses explicit comparator since default comparator would not know how to compare function references. -?> EventHandler eventName <- String() handler as Handler? default private EventHandler() EventHandler() -> n as String h as Handler eventName :=: n handler := h fire() <- rtn as Boolean: handler(eventName) //Explicit comparator — compares by name, ignoring the delegate operator <=> as pure -> other as EventHandler <- rtn as Integer: eventName <=> other.eventName //A hand-written <=> needs a hand-written #? hashing what it compares operator #? as pure <- rtn as Integer: #?eventName override operator ? as pure <- rtn as Boolean: eventName? and handler? defines record <?- Record without delegates — all default operators work fine. -?> SimpleRecord label <- "none" SimpleRecord() -> l as String label :=: l operator <=> as pure -> other as SimpleRecord <- rtn as Integer: label <=> other.label operator #? as pure <- rtn as Integer: #?label default operator defines program DelegateDemo() stdout <- Stdout() eh1 <- EventHandler("click", LogHandler) eh2 <- EventHandler("submit", LogHandler) if eh1? comparison <- eh1 <=> eh2 stdout.println(`Comparison: ${comparison}`) stdout.println(`Fire: ${eh1.fire()}`) simple1 <- SimpleRecord("alpha") simple2 <- SimpleRecord("beta") if simple1? simpleResult <- simple1 <=> simple2 stdout.println(`Simple: ${simpleResult}`)
Common mistakes
E07210 — Record has a function delegate field — 'default operator <=>' cannot be auto-generated because comparing function references has no meaningful semantics. Use 'default operator ?' (always valid) or implement comparison explicitly. See ek9 -h E07210 for details.
Incorrect:
default operator <=>
Correct:
operator <=> as pure -> other as EventHandler <- rtn as Integer: eventName <=> other.eventName
E07210 — Cannot auto-generate all default operators for records with delegates. 'default operator' would include comparators which cannot compare function references. Implement operators explicitly. See ek9 -h E07210 for details.
Incorrect:
default operator
Correct:
override operator ? as pure <- rtn as Boolean: eventName? and handler?
Other ways to ask this
- What is E07210 FUNCTION_DELEGATE_WITH_DEFAULT_OPERATORS?
- Why does EK9 reject default comparator on my record with a delegate?
- How do I compare records that contain function delegate fields?
Coming from another language?
Java: records with functional interface fields auto-generate equals/hashCode comparing by identity — usually meaningless. Kotlin: data classes with lambda fields use reference equality for lambdas. C#: records include delegates in equality using invocation list — fragile and surprising. EK9: rejects default comparison for delegate-containing records at compile time.
Keywords: E07210, comparator, comparison, default, delegate, field, function, isSet, operator, record