How do I run a callback over a collection that is held inside an Optional or Result?
← Generics · Ref: Q1372
A built-in generic container (Optional, Result) can be parameterised over another generic type - Optional of (List of String), Result of (List of String, Integer) - and its callback methods hand the FULLY-TYPED value to your function, exactly as the return methods (get/ok) do. You write the callback the same way you would over a simple element.
OPTIONAL OF A LIST - whenPresent
items <- List() of String items += "alpha" opt <- Optional(items)
printer <- (stdout) is Acceptor of List of String as function stdout.println(`present: ${$t}`) opt.whenPresent(printer) // printer receives a List of String
RESULT OF A LIST - whenOk / whenError
listResult <- Result(items, 0) onOk <- (stdout) is Acceptor of List of String as function stdout.println(`ok: ${$t}`) listResult.whenOk(onOk)
The callback parameter is the SAME type you parameterised the container with. Whether the element is a simple type (String) or itself a generic (List of String, Dict of (String, Integer)), the value you receive is the typed wrapper - never a raw internal delegate.
GUARD BEFORE get()/ok()
The callback forms (whenPresent/whenOk/whenError) fire only in the right state, so they need no guard. The value-returning forms do - guard first:
if opt? got <- opt.get()
Use the callback form when you just want to act on the value, the get form when you need it in the surrounding scope.
See Q47 for Optional. See Q48 for Result. See Q707 for Consumer/Acceptor. See Q198 for the built-in generics.
Example
defines module qa.genericsdeep.collectioncallback defines program CollectionCallbackDemo() stdout <- Stdout() items <- List() of String items += "alpha" items += "beta" // Optional of (List of String) - whenPresent hands the typed List to the callback opt <- Optional(items) printer <- (stdout) is Acceptor of List of String as function stdout.println(`present: ${$t}`) opt.whenPresent(printer) // Result of (List of String, Integer) - whenOk hands the typed List to the callback listResult <- Result(items, 0) onOk <- (stdout) is Acceptor of List of String as function stdout.println(`ok: ${$t}`) listResult.whenOk(onOk) // Value-returning form needs a guard first if opt? got <- opt.get() stdout.println(`got: ${$got}`)
Common mistakes
E08030 — Optional.get() must be guarded by a set-check first (E08030). The whenPresent callback form needs no guard because it only fires when a value is present. See ek9 -h E08030 for details.
Incorrect:
got <- opt.get()
Correct:
if opt? got <- opt.get()
Other ways to ask this
- whenPresent over an Optional of a List
- whenOk / whenError with a List value in a Result
- Pass a Consumer to a container whose element is itself a generic type
- Callback receives a List of String from an Optional
Coming from another language?
Java: optional.ifPresent(list -> ...) where list is List<String>; the type is preserved. EK9: opt.whenPresent(acceptor) where the Acceptor is 'of List of String' - identical mental model, and the compiler guarantees the callback receives the typed value even when the element is itself a parameterised type.
Keywords: container, Consumer, whenPresent, generic, whenError, parameterised, Result, callback, Optional, whenOk, Acceptor, collection, List