Blocks

Jamie Winsor edited this page May 13, 2013 · 13 revisions

Celluloid executes blocks in the sender's context. This means that each block invocation is doing a round-trip from receiver to sender and back again.

There is a class method for declaring to Celluloid that you would like the block to be executed on the receiver instead of the sender. This should be used with caution!

class DangerMouse
  include Celluloid

  execute_block_on_receiver :break_the_world

  def break_the_world
    yield
  end
end

Warnings

If you declare the block to execute on the receiver, you need to be aware of potential issues. All state which the block closes over will be shared across threads and can lead to the potential for concurrent mutation errors.

The safest way to avoid these errors is to not reference anything from the outer scope inside your block. If you do insist upon using state from the outer scope (i.e. another actor) in your block, please make sure no mutation of this state is happening after the actor is created.

DCell supports blocks via the same pattern as Celluloid. DCell depends on Ruby Marshal as its wire protocol, and Ruby presently has no standard format for marshaling Procs, which would be the only way DCell could send blocks over the wire. Because of this fact, you may not pass a block to a method invocation on a DCell actor which invokes the block on the receiver.