Class: Functional::Delay
- Inherits:
-
Synchronization::Object
- Object
- Synchronization::Object
- Functional::Delay
- Defined in:
- lib/functional/delay.rb
Overview
This is a write-once, read-many, thread safe object that can be used in concurrent systems. Thread safety guarantees cannot be made about objects contained within this object, however. Ruby variables are mutable references to mutable objects. This cannot be changed. The best practice it to only encapsulate immutable, frozen, or thread safe objects. Ultimately, thread safety is the responsibility of the programmer.
Lazy evaluation of a block yielding an immutable result. Useful for expensive operations that may never be needed.
When a Delay
is created its state is set to pending
. The value and
reason are both nil
. The first time the #value
method is called the
enclosed opration will be run and the calling thread will block. Other
threads attempting to call #value
will block as well. Once the operation
is complete the value will be set to the result of the operation or the
reason will be set to the raised exception, as appropriate. All threads
blocked on #value
will return. Subsequent calls to #value
will
immediately return the cached value. The operation will only be run once.
This means that any side effects created by the operation will only happen
once as well.
Instance Method Summary (collapse)
-
- (Boolean) fulfilled?
(also: #value?)
Has the delay been fulfilled?.
-
- (Delay) initialize { ... }
constructor
Create a new
Delay
in the:pending
state. -
- (Boolean) pending?
Is delay completion still pending?.
-
- (StandardError) reason
The exception raised when processing the block.
-
- (Boolean) rejected?
(also: #reason?)
Has the delay been rejected?.
-
- (Symbol) state
Current state of block processing.
-
- (Object) value
Return the (possibly memoized) value of the delayed operation.
Constructor Details
- (Delay) initialize { ... }
Create a new Delay
in the :pending
state.
37 38 39 40 41 42 43 44 |
# File 'lib/functional/delay.rb', line 37 def initialize(&block) raise ArgumentError.new('no block given') unless block_given? super synchronize do @state = :pending @task = block end end |
Instance Method Details
- (Boolean) fulfilled? Also known as: value?
Has the delay been fulfilled?
81 82 83 |
# File 'lib/functional/delay.rb', line 81 def fulfilled? synchronize{ @state == :fulfilled } end |
- (Boolean) pending?
Is delay completion still pending?
95 96 97 |
# File 'lib/functional/delay.rb', line 95 def pending? synchronize{ @state == :pending } end |
- (StandardError) reason
The exception raised when processing the block. Returns nil
if the
operation is still :pending
or has been :fulfilled
.
58 59 60 |
# File 'lib/functional/delay.rb', line 58 def reason synchronize{ @reason } end |
- (Boolean) rejected? Also known as: reason?
Has the delay been rejected?
88 89 90 |
# File 'lib/functional/delay.rb', line 88 def rejected? synchronize{ @state == :rejected } end |
- (Symbol) state
Current state of block processing.
49 50 51 |
# File 'lib/functional/delay.rb', line 49 def state synchronize{ @state } end |
- (Object) value
Return the (possibly memoized) value of the delayed operation.
If the state is :pending
then the calling thread will block while the
operation is performed. All other threads simultaneously calling #value
will block as well. Once the operation is complete (either :fulfilled
or
:rejected
) all waiting threads will unblock and the new value will be
returned.
If the state is not :pending
when #value
is called the (possibly
memoized) value will be returned without blocking and without performing
the operation again.
75 76 77 |
# File 'lib/functional/delay.rb', line 75 def value synchronize{ execute_task_once } end |