Issue #19326 has been updated by sdwolfz (Codruț Gușoi).
OK, I had absolutely no idea you could do that. Thanks for the suggestion! My impressions
was `instance_eval` could only be used around where a block is *written*.
Can we document this behaviour somewhere? Maybe in
https://docs.ruby-lang.org/en/3.2/Ractor.html right after the `Shareable and unshareable
objects` section. I suspect many more people will hit the same wall as I had and would not
have an easy time figuring it out.
----------------------------------------
Feature #19326: Please add a better API for passing a Proc to a Ractor
https://bugs.ruby-lang.org/issues/19326#change-101386
* Author: sdwolfz (Codruț Gușoi)
* Status: Open
* Priority: Normal
----------------------------------------
Example 1:
```ruby
class Worker
def initialize(&block)
@block = block
end
def run
Ractor.new(@block, &:call)
end
end
worker = Worker.new { 1 }
puts worker.run.take
```
Errors with:
```
<internal:ractor>:271:in `new': allocator undefined for Proc (TypeError)
from scripts/run.rb:9:in `run'
from scripts/run.rb:14:in `<main>'
```
Example 2:
```ruby
class Worker
def initialize(&block)
@block = Ractor.make_shareable(block)
end
def run
Ractor.new(@block, &:call)
end
end
worker = Worker.new { 1 }
puts worker.run.take
```
Errors with:
```
<internal:ractor>:820:in `make_shareable': Proc's self is not shareable:
#<Proc:0x00007f00394c38b8 scripts/run.rb:13> (Ractor::IsolationError)
from scripts/run.rb:5:in `initialize'
from scripts/run.rb:13:in `new'
from scripts/run.rb:13:in `<main>'
```
Example 3:
```ruby
class Worker
def initialize(&block)
@block = Ractor.make_shareable(block)
end
def run
Ractor.new(@block, &:call)
end
end
worker = Ractor.current.instance_eval { Worker.new { 1 } }
puts worker.run.take
```
Works, but having `Ractor.current.instance_eval` as a wrapper around the block is not
ideal, as Ractor is supposed to be only an implementation detail in Worker.
I know about
https://bugs.ruby-lang.org/issues/18243 and the discussion around
`proc.bind(nil)`. That would actually be ideal, as for the purposes if why I want this
functionality I don't care what `self` is in a block, and the less it has access to
the better.
The general idea of Worker is to have a Ractor be able to lazily execute an arbitrary
proc. And all the bindings it would need would be passed explicitly, either through `args`
in the constructor or through `send`/`receive`, so `self` would really not matter.
The benefit: this would make it so concurrent code can be more easily be implemented with
Ractors as currently you can execute an arbitrary proc by passing it to a Thread (but you
don't get the nice data isolation).
--
https://bugs.ruby-lang.org/