Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Result Channels

ztellman edited this page Mar 30, 2011 · 3 revisions

A result-channel represents a single potential value, as opposed to a normal channel which represents a stream of values. For instance, (read-channel channel) will return a result-channel representing the next message from the channel.

> (def ch (channel))
#'ch
> (def next-msg (read-channel ch))
#'next-msg
> next-msg
<< ... >>

Since the channel is empty, the result-channel representing the next message from the channel has no value. However, once we enqueue a message into the channel, next-msg will be realized.

> (enqueue ch "hello")
true
> next-msg
<< "hello" >>

To pull the value out of a result-channel, you can simply dereference it using @result-channel. If the result-channel hasn’t been realized yet, then the thread will block until it is. An asynchronous alternative is to use (on-success result-channel & callbacks), which will trigger the callbacks once the result-channel has been realized.

Once a result-channel is realized its value cannot be consumed. If you repeatedly register callbacks on a realized result-channel with on-success, the callbacks will always be triggered.

A result-channel can also represent a failure to realize a value. For instance, read-channel allows a timeout to be specified. Let’s see what happens if we specify a timeout of 0 ms when reading from an empty channel:

> (read-channel (channel) 0)
<< ERROR: java.util.concurrent.TimeoutException: read-channel timed out after 0 ms >>

The result-channel now contains an exception. If we subsequently enqueue a message into the channel, it will not be consumed as the operation has already failed. If we dereference this result-channel, its exception will be thrown.

We may hook into this outcome using the (on-error result-channel & callbacks). If using on-success, it’s generally prudent to also handle the error outcome. However, on-success and on-error are not the recommended ways to interact with result-channels. Instead, Lamina provides several higher-level abstractions for using result-channels effectively.

result-channels and pipelines

Pipelines represent the composition of functions, any of which may return a result-channel. If a function returns an unrealized result-channel, then the pipeline pauses until the realized value can be passed into the next function. Since the pipeline may not immediately complete, invoking a pipeline also returns a result-channel.

If any function in a pipeline throws an exception or returns a result-channel which emits an exception, then the pipeline is short-circuited and the result-channel returned by the pipeline emits the exception.

result-channels and (async …)

Wrapping a block of code in the async macro allows result-channels in its body to be treated like real values. This can be a powerful tool, allowing values be computed locally, on other threads, or even other systems without affecting the structure of your code.

Clone this wiki locally