Class: Garcon::IVar

Inherits:
Object show all
Includes:
Obligation, Observable
Defined in:
lib/garcon/task/ivar.rb

Overview

An ‘IVar` is like a future that you can assign. As a future is a value that is being computed that you can wait on, an `IVar` is a value that is waiting to be assigned, that you can wait on. `IVars` are single assignment and deterministic.

Then, express futures as an asynchronous computation that assigns an ‘IVar`. The `IVar` becomes the primitive on which [futures](Future) and [dataflow](Dataflow) are built.

An ‘IVar` is a single-element container that is normally created empty, and can only be set once. The I in `IVar` stands for immutable. Reading an `IVar` normally blocks until it is set. It is safe to set and read an `IVar` from different threads.

If you want to have some parallel task set the value in an ‘IVar`, you want a `Future`. If you want to create a graph of parallel tasks all executed when the values they depend on are ready you want `dataflow`. `IVar` is generally a low-level primitive.

Examples:

Create, set and get an ‘IVar`

ivar = Garcon::IVar.new
ivar.set 14
ivar.get #=> 14
ivar.set 2 # would now be an error

Direct Known Subclasses

Future

Instance Method Summary collapse

Methods included from Observable

#count_observers, #delete_observer, #delete_observers, #with_observer

Methods included from Obligation

#complete?, #exception, #fulfilled?, #incomplete?, #pending?, #reason, #rejected?, #state, #unscheduled?, #value, #value!, #wait, #wait!

Methods included from Dereferenceable

#value

Constructor Details

#initialize(value = NO_VALUE, opts = {}) ⇒ IVar

Create a new ‘IVar` in the `:pending` state with the (optional) initial value.

Parameters:

  • value (Object) (defaults to: NO_VALUE)

    The initial value.

  • opts (Hash) (defaults to: {})

    the options to create a message with.

Options Hash (opts):

  • :dup_on_deref (String) — default: false

    Call ‘#dup` before returning the data.

  • :freeze_on_deref (String) — default: false

    Call ‘#freeze` before returning the data.

  • :copy_on_deref (String) — default: nil

    Cll the given ‘Proc` passing the internal value and returning the value returned from the proc.



76
77
78
79
80
81
82
83
84
85
86
# File 'lib/garcon/task/ivar.rb', line 76

def initialize(value = NO_VALUE, opts = {})
  init_obligation
  self.observers = CopyOnWriteObserverSet.new
  set_deref_options(opts)

  if value == NO_VALUE
    @state = :pending
  else
    set(value)
  end
end

Instance Method Details

#add_observer(bsrver = nil, func = :update, &block) ⇒ Object

Add an observer on this object that will receive notification on update.

Upon completion the ‘IVar` will notify all observers in a thread-safe way. The `func` method of the observer will be called with three arguments: the `Time` at which the `Future` completed the asynchronous operation, the final `value` (or `nil` on rejection), and the final `reason` (or `nil` on fulfillment).

Parameters:

  • observer (Object)

    The object that will be notified of changes.

  • func (Symbol) (defaults to: :update)

    Symbol naming the method to call when the ‘Observable` has changes`



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/garcon/task/ivar.rb', line 102

def add_observer(bsrver = nil, func = :update, &block)
  if observer && block
    raise ArgumentError, 'cannot provide both an observer and a block'
  end
  direct_notification = false

  if block
    observer = block
    func     = :call
  end

  mutex.synchronize do
    if event.set?
      direct_notification = true
    else
      observers.add_observer(observer, func)
    end
  end

  observer.send(func, Time.now, self.value, reason) if direct_notification
  observer
end

#fail(reason = StandardError.new) ⇒ IVar

Set the ‘IVar` to failed due to some error and wake or notify all threads waiting on it.

Parameters:

  • reason (Object) (defaults to: StandardError.new)

    For the failure.

Returns:

Raises:

  • (Garcon::MultipleAssignmentError)

    If the ‘IVar` has already been set or otherwise completed.



150
151
152
# File 'lib/garcon/task/ivar.rb', line 150

def fail(reason = StandardError.new)
  complete(false, nil, reason)
end

#set(value) ⇒ IVar

Set the ‘IVar` to a value and wake or notify all threads waiting on it.

Parameters:

  • value (Object)

    The value to store in the ‘IVar`.

Returns:

Raises:

  • (Garcon::MultipleAssignmentError)

    If the ‘IVar` has already been set or otherwise completed.



135
136
137
# File 'lib/garcon/task/ivar.rb', line 135

def set(value)
  complete(true, value, nil)
end