hamstergem / hamster

Efficient, Immutable, Thread-Safe Collection classes for Ruby
Other
1.89k stars 94 forks source link

push() returns a new Deque instead of an in-place data structure change? #165

Closed xbeta closed 9 years ago

xbeta commented 9 years ago

I read this in the API doc that it returns a new Deque in every push(), instead of a reusing the same Deque and perform an in-place change. Why is this behavior even consider to be implemented???

push(item) ⇒ Deque (also: #enqueue)

Return a new Deque with item added at the end.

The stdlib ruby core Queue doesn't have that behavior.

dubek commented 9 years ago

@xbeta: This is intended. To quote from the README:

Hamster collections are immutable. Whenever you modify a Hamster collection, the original is preserved and a modified copy is returned. This makes them inherently thread-safe and shareable. At the same time, they remain CPU and memory-efficient by sharing between copies.

This is true for all Hamster's data structures: Hamster::Hash, Hamster::Vector, and so on. So a #push or a #set on a Hamster::Vector instance will return a new one, unlike Ruby's built-in Array which will modify the instance in-place.

alexdowad commented 9 years ago

In any case, @xbeta, thank you for your interest in Hamster! (And thanks to @dubek for explaining things.) If you need a mutable queue, I suggest you use the one in the Ruby standard library.

xbeta commented 9 years ago

@dubek thanks for the explanation, but what's stopping one thread push() and another thread pop() at the same time in a concurrency world?

def initialize()
  @nums = Hamster::Deque.new()
end
..
def add(num)
   # because hamster's deque is immutable
   @nums = @nums.push(num)
end
alexdowad commented 9 years ago

@xbeta, nothing is stopping 2 threads from doing those things at the same time. You can "stop" them by locking, just the same as with a mutable queue. Or, you have another option, which doesn't exist with a mutable queue: you can retry an atomic compare-and-swap until it succeeds. Or, your queue might exist only on the stack of one thread, meaning it can never be shared with another thread.