How do I use BiConsumer and BiAcceptor with two parameters?
← Generics · Ref: Q711
BiConsumer and BiAcceptor are the void-returning two-parameter function types. They process two values 't' and 'u' without returning a result.
BICONSUMER IS PURE
BiConsumer of (T, U) takes parameters 't' and 'u' and returns nothing. Being pure, it cannot call impure functions:
validator <- () is BiConsumer of (String, Integer) as pure function require t? and u?
BIACCEPTOR IS IMPURE
BiAcceptor of (T, U) has the same signature but is NOT pure:
logger <- () is BiAcceptor of (String, Integer) as function stdout <- Stdout() stdout.println(`Name: ${t}, Age: ${u}`)
USE CASES
BiConsumer: Pure validation of two related values.
BiAcceptor: Logging, formatting, or storing pairs of values.
See Q54 for pure vs impure concepts. See Q707 for single-parameter Consumer/Acceptor.
Example
defines module qa.genericsdeep.biconsumerbiacceptor defines function <?- Helper that validates a pair using a pure BiConsumer. -?> validateWith() as pure -> name as String age as Integer validator as BiConsumer of (String, Integer) validator(name, age) <?- Helper that processes a pair using an impure BiAcceptor. -?> processPair() -> name as String age as Integer handler as BiAcceptor of (String, Integer) handler(name, age) defines program BiConsumerBiAcceptorDemo() stdout <- Stdout() //BiConsumer: pure, validation only //Body uses 't' and 'u' — from BiConsumer's signature validator <- () is BiConsumer of (String, Integer) as pure function require t? and u? validateWith("Steve", 42, validator) stdout.println("BiConsumer validation passed") //BiAcceptor: impure, can log logger <- () is BiAcceptor of (String, Integer) as function stdout <- Stdout() stdout.println(`Name: ${t}, Age: ${u}`) processPair("Alice", 30, logger) //Direct call validator("Bob", 25) stdout.println("Direct BiConsumer call passed")
Common mistakes
E05150 — BiConsumer is pure — dynamic functions extending BiConsumer 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 BiConsumer of (String, Integer) as function
Correct:
() is BiConsumer of (String, Integer) as pure function
Other ways to ask this
- What is the difference between BiConsumer and BiAcceptor?
- How do I create a BiConsumer of (String, Integer)?
- When should I use BiAcceptor instead of BiConsumer?
Coming from another language?
Java: java.util.function.BiConsumer<T,U> — no purity distinction. Kotlin: (T, U) -> Unit — no pure/impure variants. Rust: Fn(&T, &U) vs FnMut(&T, &U) — structural. Go: func(T, U) — no purity. C#: Action<T1, T2> — no purity concept. EK9: BiConsumer (pure) vs BiAcceptor (impure) — compile-time enforced purity.
Keywords: callback, pure, void, function-type, side-effect, biconsumer, biacceptor, generic, impure, two-parameter, pair