How do I use Supplier and Producer to create values?
← Generics · Ref: Q708
Supplier and Producer are the no-parameter function types that return a value. They differ only in purity.
SUPPLIER IS PURE
Supplier of T takes no parameters and returns 'r' of type T. Being pure, it is free of side effects (it cannot mutate or reassign anything it does not own):
factory <- () is Supplier of String as pure function r: "Default"
A pure Supplier is a side-effect-free factory. Pure does not mean deterministic: pure-marked built-ins such as GUID() or SystemClock() can be called from a pure Supplier, which then returns a different value each time.
PRODUCER IS IMPURE
Producer of T has the same signature but is NOT pure, so it can read external state:
generator <- () is Producer of String as function r: "Generated"
Producer allows side effects in value creation.
FACTORY PATTERN
Use Supplier for side-effect-free factories and Producer for stateful ones:
obtainValue()
-> factory as Supplier of String
<- result as String: factory()
See Q54 for pure vs impure concepts. See Q649 for generic function implementation rules.
Example
defines module qa.genericsdeep.supplierproducer defines function <?- Helper that uses a Supplier to get a value. Pure context — only pure Suppliers can be passed. -?> obtainValue() as pure -> factory as Supplier of String <- result as String: factory() <?- Helper that uses a Producer to get a value. Impure context — Producer can have side effects. -?> generateValue() -> factory as Producer of String <- result as String: factory() defines program SupplierProducerDemo() stdout <- Stdout() //Supplier: pure, deterministic factory //Body sets 'r' — the return variable from Supplier's signature nameFactory <- () is Supplier of String as pure function r: "DefaultName" name <- obtainValue(nameFactory) stdout.println(`Supplier result: ${name}`) //Producer: impure, can access external state greetingFactory <- () is Producer of String as function r: "Hello from Producer" greeting <- generateValue(greetingFactory) stdout.println(`Producer result: ${greeting}`) //Direct call on dynamic function variable directResult <- nameFactory() stdout.println(`Direct Supplier: ${directResult}`)
Common mistakes
E05150 — Supplier is pure — dynamic functions extending Supplier must use 'as pure function', not just 'as function'. The compiler requires the purity of the implementation to match its pure super type. See ek9 -h E05150 for details.
Incorrect:
() is Supplier of String as function
Correct:
() is Supplier of String as pure function
Other ways to ask this
- What is the difference between Supplier and Producer in EK9?
- How do I create a factory function with Supplier of T?
- When should I use Producer instead of Supplier?
Coming from another language?
Java: java.util.function.Supplier<T> — no purity distinction, can have side effects. Kotlin: () -> T — no pure/impure variants. Rust: Fn() -> T (pure) vs FnMut() -> T (stateful) — structural distinction. Go: func() T — no purity enforcement. C#: Func<T> — no purity concept. EK9: Supplier (pure, side-effect free) vs Producer (impure, can be stateful) — compile-time enforced.
Keywords: side-effect, supplier, function-type, create, return, factory, pure, no-parameter, impure, generic, producer