What can and cannot be called from a pure method?
← Purity Contracts · Ref: Q566
A pure method can only call other pure methods and functions. Calling a non-pure method from a pure context produces error E08130.
THE RULE
Pure can only call pure. If method A is pure, every method A calls must also be pure. This creates a trust chain: if the entry point is pure, the entire execution path is pure.
THE ERROR: E08130
Calling a non-pure function or method from within a pure context produces E08130: non-pure call in pure scope.
WHAT PURE CAN CALL
Other pure methods on the same class. Pure methods on other objects. Built-in pure operators (+, -, *, /, comparisons). Pure functions defined in the module.
WHAT PURE CANNOT CALL
Non-pure methods (E08130). Methods that use mutation operators internally. Functions not marked as pure.
I/O EXCEPTION
Stdout, Stderr, Stdin, and other I/O types carry the IO marker trait. Methods on IO types are allowed in pure context because I/O is considered a separate concern from data mutation.
BUILT-IN PURE METHODS
Most accessor methods on built-in types (length, upperCase, contains) are pure. Mutation methods (+=, append, etc.) are not.
See Q560 for pure method basics. See Q561 for purity in overrides. See Q273 for purity as security boundary. See Q54 for Consumer (pure) vs Acceptor (non-pure).
Example
defines module qa.purity.restrictions defines function //Pure function: only uses pure operations doubleValue() as pure -> number as Integer <- result as Integer: number + number //Pure function calling another pure function quadrupleValue() as pure -> number as Integer <- result as Integer: doubleValue(doubleValue(number)) defines class Processor prefix <- String() Processor() -> prefix as String this.prefix: prefix //Pure method: calls only pure functions and methods transform() as pure -> text as String <- rtn as String: `${prefix}: ${text.upperCase()}` //Pure method calling pure function processNumber() as pure -> number as Integer <- rtn as String: `${prefix}: ${quadrupleValue(number)}` //Non-pure method: this is fine, just cannot be called from pure context logAndTransform() -> text as String <- rtn as String: `${prefix}: ${text.upperCase()}` default operator ? defines program PureMethodRestrictionsDemo() stdout <- Stdout() //Pure function calls stdout.println(`Double 5: ${doubleValue(5)}`) stdout.println(`Quadruple 5: ${quadrupleValue(5)}`) //Pure method calls proc <- Processor("APP") stdout.println(proc.transform("hello")) stdout.println(proc.processNumber(7)) //Non-pure method call (allowed from program, which is non-pure) stdout.println(proc.logAndTransform("world"))
Common mistakes
E50001 — Renaming the variable means later references to 'proc' become unresolved, triggering E50001. See ek9 -h E50001 for details.
Incorrect:
procXYZ <- Processor("APP")
Correct:
proc <- Processor("APP")
E50001 — Referencing a variable 'procXYZ' that was never declared triggers E50001. The original variable was 'proc'. See ek9 -h E50001 for details.
Incorrect:
stdout.println(procXYZ.transform("hello"))
Correct:
stdout.println(proc.transform("hello"))
Other ways to ask this
- What is E08130 non-pure call in pure scope?
- Can a pure method call a non-pure method?
- How does EK9 enforce pure call chains?
Coming from another language?
Java: no call chain purity enforcement. Kotlin: no purity tracking. Rust: no purity annotation on function calls. Haskell: pure functions cannot call IO without the monad. EK9: E08130 enforces pure-calls-pure chain, I/O types are exempted via IO trait.
Keywords: scope, pure, side-effect, call, chain, non-pure, migrate, immutable, purity, function, E08130, contract, restriction, trust