From: sdwolfz via ruby-core <ruby-core@...>
Date: 2023-01-21T07:07:40+00:00
Subject: [ruby-core:111949] [Ruby master Feature#19326] Please add a better API for passing a Proc to a Ractor

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/

 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/