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 always returns the same value:

  factory <- () is Supplier of String as pure function
    r: "Default"

A pure Supplier is a constant factory — deterministic and safe.

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 deterministic 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, deterministic) vs Producer (impure, can be stateful) — compile-time enforced.

Keywords: no-parameter, pure, factory, return, create, function-type, supplier, side-effect, producer, generic, impure