An Actor is the most primitive unit of computation: it receives a message and performs a computation.

An actor is analogous to an object in an object-oriented languages. An object receives a message (a method call) and does something depending on which message it receives (the method we are calling). The main difference is that actors are completely isolated from each other, and they will never share memory. It’s also worth mentioning that an actor can maintain a private state that should never be changed directly by another actor.

For a quick introduction to Actor models, see this article.

The API of Rocket.jl's Actors is similar to RxJS subscribers.

First example

The following example implements an Actor that retains each received value from an Observable.

using Rocket

struct CustomKeepActor <: Actor{Int}

    CustomKeepActor() = new(Vector{Int}())

Rocket.on_next!(actor::CustomKeepActor, data::Int) = push!(actor.values, data)
Rocket.on_error!(actor::CustomKeepActor, err)      = error(err)
Rocket.on_complete!(actor::CustomKeepActor)        = println("Completed!")

source     = from([ 1, 2, 3 ])
keep_actor = CustomKeepActor()
subscribe!(source, keep_actor)

# Logs
# Completed!


# Logs
# [1, 2, 3]

An actor may be not interested in the values itself, but merely the completion of an event. In this case, Rocket.jl provides a CompletionActor abstract type.

using Rocket

struct CompletionNotificationActor <: CompletionActor{Int} end

Rocket.on_complete!(::CompletionNotificationActor) = println("Completed!")

source     = from([ 1, 2, 3 ])
subscribe!(source, CompletionNotificationActor());

# Logs
# Completed

Lambda actor

For debugging purposes it may be convenient to work with a LambdaActor. This provides an interface that defines callbacks for "next", "error" and "complete" events.

using Rocket

source = from([1, 2, 3])

subscribe!(source, lambda(
    on_next     = (d) -> println(d),
    on_error    = (e) -> error(e),
    on_complete = ()  -> println("Completed")

# Logs
# 1
# 2
# 3
# Completed