From: "Eregon (Benoit Daloze) via ruby-core" Date: 2025-12-08T10:28:15+00:00 Subject: [ruby-core:124053] [Ruby Feature#21767] Consider procs which `self` is Ractor-shareable as Ractor shareable Issue #21767 has been updated by Eregon (Benoit Daloze). Naturally it would need to follow the rules of `Ractor.shareable_proc` (#21557) regarding accessing captured variables: * Any captured variable must not be reassigned * The value of every captured variable must be shareable (not sure how common that is the case, so this might limit the usefulness of this proposal quite a bit in practice) Besides that, it sounds convenient that Procs which satisfy those rules (i.e. no exception when `Ractor.shareable_proc` is called on them) + already have a shareable `self` are automatically `shareable`. It's just of course that Procs already having a shareable `self` are not very common. There is one incompatibility though, that by making that Proc shareable it can behave differently on the main Ractor than before this proposal: ```ruby class Foo a = 42 SOME_PROC = -> { eval "a" } a += 1 SOME_PROC_SHAREABLE = Ractor.shareable_proc(&SOME_PROC) end p Foo::SOME_PROC.call puts Foo::SOME_PROC_SHAREABLE.call ``` `SOME_PROC` is not detected as accessing captured variables because of `eval`. If the Proc is not shareable it still works as it always did (return 43). If `SOME_PROC` is made automatically shareable by this proposal then it now raises an error, as simulated by `SOME_PROC_SHAREABLE`: ``` $ ruby auto_shareable_proc.rb 43 (eval at auto_shareable_proc.rb:3): (eval at auto_shareable_proc.rb:3):1: can not access variable 'a' from isolated Proc (SyntaxError) ``` And the same when using `binding` inside the block. Also `SOME_PROC.binding` doesn't work for a shareable Proc. ---------------------------------------- Feature #21767: Consider procs which `self` is Ractor-shareable as Ractor shareable https://bugs.ruby-lang.org/issues/21767#change-115485 * Author: osyoyu (Daisuke Aritomo) * Status: Open ---------------------------------------- I would like to allow procs which `self` is Ractor-shareable to be automatically eligible as shareable, without an explicit `Ractor.make_shareable` call. ```ruby class C PROC = proc { p ARRAY }.freeze end Ractor.new { C::PROC.call }.value # Allow this, since `C` is shareable ``` Proposal is: Consider procs/lambdas which meet the following condition as Ractor-shareable. - The proc is frozen. - The proc's `self` is shareable. This proposal is has taken inspiration from #21033 . ## Usecase The main usecase in mind is procs/lambdas in class-level constants. Some libraries store procs in constants as a convenient place for library-wide logic. Those procs usually do not access unshareable state, thus conceptually safe to be shared across Ractors. However, the current limitation completely blocks this. Examples may be found in ruby/ruby, and I have submitted a pull request to migrate one to `Ractor.shareable_proc`. ```ruby class Pathname SAME_PATHS = if File::FNM_SYSCASE.nonzero? # Avoid #zero? here because #casecmp can return nil. proc {|a, b| a.casecmp(b) == 0} else proc {|a, b| a == b} end end ``` https://github.com/search?q=repo%3Aruby%2Fruby%20%2F(%3F-i)%5BA-Z%5D%20%3D%20(proc%7Clambda)%2F&type=code More examples can be found in public code. https://github.com/search?q=language%3Aruby+%2F%28%3F-i%29%5BA-Z%5D+%3D+%28proc%7Clambda%29%2F&type=code It can be observed that a good portion of these do not access unshareable state. Appending `.freeze` would be much more acceptable than redefining using `Ractor.shareable_proc`, which is a Ruby 4.0-only feature. ## Discussion: Change of behavior when illegal access occurs in proc Consider this code. The proc accesses non-frozen `C::ARRAY`, which is against the rules of Ractors regardless of this patch. ```ruby class C ARRAY = [] PROC = proc { p ARRAY } end # Still illegal since C::ARRAY is not shareable Ractor.new { C::PROC.call }.value ``` This code used to raise on `C::PROC.call` (`can not access non-shareable objects in constant C::PROC by non-main Ractor.`). When this patch is applied, it will raise on `p ARRAY` (`can not access non-shareable objects in constant C::ARRAY by non-main ractor.`). This could be debatable change. If this is not acceptable, I'd like to revisit #21033 . -- 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/lists/ruby-core.ml.ruby-lang.org/