igrigorik/em-synchrony — Issue #75: Potential improvement to EM::Synchrony.sync handling of Deferrables called with multiple arguments
Author: slyphon
Created: 2011-10-29 03:16:11+00:00
State: open

Hi!

I'm working on providing an em-synchrony friendly version of [ZK::EventMachine](https://github.com/slyphon/zk-eventmachine/tree/dev/synchrony), but have run into trouble with the way that EM::Synchrony.sync handles callbacks that have their `succeed` method invoked with multiple arguments. I make extensive use of this pattern throughout my code, so for me this is a pretty important thing to have working :)

Below I have an example fix for sync. I created a fork and branch of em-synchrony and made the change, but I couldn't figure out how to set up all of the required dependencies to run the specs.

I've included below a small demonstration of the problem (for me) and the proposed fix. If it's easier for you, you can also check out [a gist](https://gist.github.com/1324024) of this code and run it that way.

The change is pretty minor, if you can instruct me on how to configure mongo and mysql, etc. so I can run the test suite, i'd be happy to. If you don't mind making the change in your environment and seeing if there are any ill effects, that'd work too.

```ruby
#!/usr/bin/env ruby

require 'rubygems'
require 'eventmachine'
require 'em-synchrony'

module EventMachine
module Synchrony
def self.new_sync(df)
f = Fiber.current
xback = proc {|*args|
if f == Fiber.current
return *args
else
f.resume(*args)
end
}
df.callback &xback
df.errback &xback

Fiber.yield
end
end
end

def gimme_deferreds
a, b = EM::DefaultDeferrable.new, EM::DefaultDeferrable.new

EM.next_tick do
a.succeed(1, 2, [:foo, :bar])
b.succeed(:single_arg)
end

return a, b
end

def current_implementation
EM.synchrony do
a, b = gimme_deferreds

rval = EM::Synchrony.sync(a)
puts "a rval: #{rval.inspect}"

rval = EM::Synchrony.sync(b)
puts "b rval: #{rval.inspect}"

EM.next_tick { EM.stop_event_loop }
end
end

def proposed_fix
EM.synchrony do
a, b = gimme_deferreds

rval = EM::Synchrony.new_sync(a)
puts "a rval: #{rval.inspect}"

rval = EM::Synchrony.new_sync(b)
puts "b rval: #{rval.inspect}"

EM.next_tick { EM.stop_event_loop }
end
end

if __FILE__ == $0
puts <<-EOS
call signature:
a.succeed(1, 2, [:foo, :bar])
b.succeed(:single_arg)

EOS

puts "this is the return value of the current implementation:"
current_implementation

puts "\nthis is the proposed change:"
proposed_fix
end

__END__

call signature:
a.succeed(1, 2, [:foo, :bar])
b.succeed(:single_arg)

this is the return value of the current implementation:
a rval: 1
b rval: :single_arg

this is the proposed change:
a rval: [1, 2, [:foo, :bar]]
b rval: :single_arg
```

Thanks!
Jonathan