From: Tony Arcieri Date: 2011-06-18T07:54:35+09:00 Subject: Re: [ANN] celluloid 0.0.3: a concurrent object framework for Ruby --20cf3033451ddf948704a5f04497 Content-Type: text/plain; charset=ISO-8859-1 On Fri, Jun 17, 2011 at 4:25 PM, David Masover wrote: > Speaking of semantics, my biggest problems were: > > - Is there a way to handle exceptions in a Ruby-esque way? > > It looks like I have to explicitly trap actor exceptions. But this is a > place > I have to be aware that this is an actor and not just a Ruby object. When making synchronous calls, exceptions which occur in the context of the receiver are automatically reraised in the caller just like any other Ruby object, regardless of if you're using any actor-specific features like linking or trapping exits. It will also crash the receiver. Your parallel map is a perfect example of what I'd actually want here: If an > exception is raised, re-raise that exception when I try to call methods on > the > actor, rather than DeadActorException. Is there a reason not to do that? > I think reraising the original exception in the caller context gives the caller appropriate context to bail out of whatever they're doing and avoid making subsequent calls at all. Other threads may be trying to make calls, and if an exception entirely unrelated to the calls they're making is raised because the actor is dead, I think that'd be rather confusing. - How do you handle cycles? > I don't, but they can be detected if you don't mind a bit of a performance penalty. For that I need to track chains of synchronous calls and detect if the receiver of a given method exists earlier in the call chain. If so, Celluloid can raise an exception in the caller context indicating that a deadlock would occur. This is a bit of a glaring deficiency right now. First, 'self' wouldn't be an actor reference, it'd be the object itself, > right? Yes. I provide Celluloid.current_actor to use in lieu of self. This feels a bit ugly, but I don't know of any way to redefine self (nor do I think that'd be a particularly good idea either) > Couple other annoyances: > > - Why spawn instead of new? It seems like if I've decided to make > something > an actor, it's going to expect to be an actor most of the time -- it's hard > to > imagine a case where I want the original 'new' instead. > This is a good point. I could easily redefine new to have the same behavior as spawn. > I really don't like the registry -- one flat namespace of actors? Ew. But > I'm not really sure how to solve this -- some sort of super-reference, > which > points to the currently-alive actor from a given supervisor? But then I > might > send something which asynchronously kills the actor, and I'll get a fresh > actor for the next line, which seems like a bad thing. There needs to be > some > clean semantics for "Give me a reference to the currently-alive version of > this actor" which doesn't rely on a global, flat registry. > I don't know of a better solution. This is the same approach Erlang uses. The only evolution it's seen in recent history is systems like Ulf Wiger's gproc. > And a thought: I just had every method return a future. If people wanted > something to run asynchronously, all they had to do is ignore the future. > The > downside is that this makes it hard to force things to be synchronous. I > actually thought of this as a good thing -- if I make the call up at the > top > of a method, and don't use the result till the bottom, that's some surprise > parallelism right there. The biggest problem is that if there's an > exception, > you don't know about it until the future is resolved. > That's an interesting approach, but a bit different than the one I'm shooting for in Celluloid, where I want concurrent objects to quack like normal Ruby objects as much as possible. -- Tony Arcieri --20cf3033451ddf948704a5f04497--