[ruby-core:120617] [Ruby master Feature#21028] Method for finding why an object isn't Ractor shareable

Issue #21028 has been reported by tenderlovemaking (Aaron Patterson). ---------------------------------------- Feature #21028: Method for finding why an object isn't Ractor shareable https://bugs.ruby-lang.org/issues/21028 * Author: tenderlovemaking (Aaron Patterson) * Status: Open ---------------------------------------- `Ractor.shareable?` is easy to use, but if it returns false I would like to be able to figure out what object is causing the data structure to _not_ be Ractor shareable. The context is that I'm trying to make some complex data structures in Rails deeply frozen. If they are deeply frozen they _should_ be Ractor shareable, but `Ractor.shareable?` is returning `false` and it's hard for me to figure out _why_. I would like a method that would either return all unshareable references, or a method that takes a block and unshareable references are yielded to the block. A method like `Ractor.unshareable_references?` or maybe `Ractor.shareable?(obj) { |not_shareable_obj| }` would be very helpful for discovering why an object is not shareable. Thanks! -- https://bugs.ruby-lang.org/

Issue #21028 has been updated by tenderlovemaking (Aaron Patterson). Assignee set to tenderlovemaking (Aaron Patterson) ---------------------------------------- Feature #21028: Method for finding why an object isn't Ractor shareable https://bugs.ruby-lang.org/issues/21028#change-111467 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Assignee: tenderlovemaking (Aaron Patterson) ---------------------------------------- `Ractor.shareable?` is easy to use, but if it returns false I would like to be able to figure out what object is causing the data structure to _not_ be Ractor shareable. The context is that I'm trying to make some complex data structures in Rails deeply frozen. If they are deeply frozen they _should_ be Ractor shareable, but `Ractor.shareable?` is returning `false` and it's hard for me to figure out _why_. I would like a method that would either return all unshareable references, or a method that takes a block and unshareable references are yielded to the block. A method like `Ractor.unshareable_references?` or maybe `Ractor.shareable?(obj) { |not_shareable_obj| }` would be very helpful for discovering why an object is not shareable. Thanks! -- https://bugs.ruby-lang.org/

Issue #21028 has been updated by luke-gru (Luke Gruber). I suspect it's probably a `Proc` object. The feature sounds good to me, and wouldn't be hard to implement I think. ---------------------------------------- Feature #21028: Method for finding why an object isn't Ractor shareable https://bugs.ruby-lang.org/issues/21028#change-111471 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Assignee: tenderlovemaking (Aaron Patterson) ---------------------------------------- `Ractor.shareable?` is easy to use, but if it returns false I would like to be able to figure out what object is causing the data structure to _not_ be Ractor shareable. The context is that I'm trying to make some complex data structures in Rails deeply frozen. If they are deeply frozen they _should_ be Ractor shareable, but `Ractor.shareable?` is returning `false` and it's hard for me to figure out _why_. I would like a method that would either return all unshareable references, or a method that takes a block and unshareable references are yielded to the block. A method like `Ractor.unshareable_references?` or maybe `Ractor.shareable?(obj) { |not_shareable_obj| }` would be very helpful for discovering why an object is not shareable. Thanks! -- https://bugs.ruby-lang.org/

Issue #21028 has been updated by osyoyu (Daisuke Aritomo). +1 for this feature. It is quite hard to find out that a rb_data_type_t in the deep is lacking the `RUBY_TYPED_FROZEN_SHAREABLE` flag. ---------------------------------------- Feature #21028: Method for finding why an object isn't Ractor shareable https://bugs.ruby-lang.org/issues/21028#change-111731 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Assignee: tenderlovemaking (Aaron Patterson) ---------------------------------------- `Ractor.shareable?` is easy to use, but if it returns false I would like to be able to figure out what object is causing the data structure to _not_ be Ractor shareable. The context is that I'm trying to make some complex data structures in Rails deeply frozen. If they are deeply frozen they _should_ be Ractor shareable, but `Ractor.shareable?` is returning `false` and it's hard for me to figure out _why_. I would like a method that would either return all unshareable references, or a method that takes a block and unshareable references are yielded to the block. A method like `Ractor.unshareable_references?` or maybe `Ractor.shareable?(obj) { |not_shareable_obj| }` would be very helpful for discovering why an object is not shareable. Thanks! -- https://bugs.ruby-lang.org/

Issue #21028 has been updated by mame (Yusuke Endoh). Is `ObjectSpace.reachable_objects_from` usable for the use case? It's a bit tedious, but I think it's more flexible not only to get an unshareable object, but also to get the path to the object in question. ```ruby require "objspace" def find_path_to_unshareable_object(obj, path = [], visited = {}) path += [obj] return if visited[obj] visited[obj] = true return if Ractor.shareable?(obj) objs = ObjectSpace.reachable_objects_from(obj) return path if objs.all? { Ractor.shareable?(it) } objs.each do |obj2| res = find_path_to_unshareable_object(obj2, path, visited) return res if res end return nil end pp *find_path_to_unshareable_object([1, 2, 3, "str".freeze, { :key => -> {} }]) #=> [1, 2, 3, "str", {key: #<Proc:0x00007f0a38e0ff30 t.rb:20 (lambda)>}] #=> {key: #<Proc:0x00007f0a38e0ff30 t.rb:20 (lambda)>} #=> #<Proc:0x00007f0a38e0ff30 t.rb:20 (lambda)> #=> main ``` ---------------------------------------- Feature #21028: Method for finding why an object isn't Ractor shareable https://bugs.ruby-lang.org/issues/21028#change-111874 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Assignee: tenderlovemaking (Aaron Patterson) ---------------------------------------- `Ractor.shareable?` is easy to use, but if it returns false I would like to be able to figure out what object is causing the data structure to _not_ be Ractor shareable. The context is that I'm trying to make some complex data structures in Rails deeply frozen. If they are deeply frozen they _should_ be Ractor shareable, but `Ractor.shareable?` is returning `false` and it's hard for me to figure out _why_. I would like a method that would either return all unshareable references, or a method that takes a block and unshareable references are yielded to the block. A method like `Ractor.unshareable_references?` or maybe `Ractor.shareable?(obj) { |not_shareable_obj| }` would be very helpful for discovering why an object is not shareable. Thanks! -- https://bugs.ruby-lang.org/

Issue #21028 has been updated by osyoyu (Daisuke Aritomo). I have been relying a lot on @mame 's snippet when programming with Ractors. It has been very useful to find why a library function / constant violates the rules of Ractors. I have opened a pull request to add `ObjectSpace#find_paths_to_unshareable_objects`, a version of this method which returns all unshareable objects which can be traced from `obj`. https://github.com/ruby/ruby/pull/13963 ```ruby require 'objspace' def find_paths_to_unshareable_objects(obj) return to_enum(__method__, obj) if !block_given? queue = [[obj, []]] visited = Set.new while current = queue.shift current_obj, current_path = current visited.add(current_obj.object_id) if !Ractor.shareable?(current_obj) yield current_path + [current_obj] ObjectSpace.reachable_objects_from(current_obj).each do |reachable| if !reachable.is_a?(ObjectSpace::InternalObjectWrapper) && !visited.include?(reachable.object_id) queue.push([reachable, current_path + [current_obj]]) end end end end end # Paths to all unshareable objects are yielded pp *find_paths_to_unshareable_objects([1, 2, 3, +"str", { :key => -> {} }]) #=> [[1, 2, 3, "str", {key: #<Proc:0x00007f22b7a5e598 rac.rb:25 (lambda)>}]] #=> [[1, 2, 3, "str", {key: #<Proc:0x00007f22b7a5e598 rac.rb:25 (lambda)>}], "str"] #=> [[1, 2, 3, "str", {key: #<Proc:0x00007f22b7a5e598 rac.rb:25 (lambda)>}], {key: #<Proc:0x00007f22b7a5e598 rac.rb:25 (lambda)>}] #=> [[1, 2, 3, "str", {key: #<Proc:0x00007f22b7a5e598 rac.rb:25 (lambda)>}], {key: #<Proc:0x00007f22b7a5e598 rac.rb:25 (lambda)>}, #<Proc:0x00007f22b7a5e598 rac.rb:25 (lambda)>] #=> [[1, 2, 3, "str", {key: #<Proc:0x00007f22b7a5e598 rac.rb:25 (lambda)>}], {key: #<Proc:0x00007f22b7a5e598 rac.rb:25 (lambda)>}, #<Proc:0x00007f22b7a5e598 rac.rb:25 (lambda)>, main] ``` ---------------------------------------- Feature #21028: Method for finding why an object isn't Ractor shareable https://bugs.ruby-lang.org/issues/21028#change-114151 * Author: tenderlovemaking (Aaron Patterson) * Status: Feedback * Assignee: tenderlovemaking (Aaron Patterson) ---------------------------------------- `Ractor.shareable?` is easy to use, but if it returns false I would like to be able to figure out what object is causing the data structure to _not_ be Ractor shareable. The context is that I'm trying to make some complex data structures in Rails deeply frozen. If they are deeply frozen they _should_ be Ractor shareable, but `Ractor.shareable?` is returning `false` and it's hard for me to figure out _why_. I would like a method that would either return all unshareable references, or a method that takes a block and unshareable references are yielded to the block. A method like `Ractor.unshareable_references?` or maybe `Ractor.shareable?(obj) { |not_shareable_obj| }` would be very helpful for discovering why an object is not shareable. Thanks! -- https://bugs.ruby-lang.org/

Issue #21028 has been updated by osyoyu (Daisuke Aritomo). A suggestion from @ko1 was to make this a block argument of `Ractor.make_shareable`. However I'd rather prefer this to be a method of its own, since the "make shareable as much as possible" behavior isn't always desired, especially when the intention is to make libraries Ractor-compatible by default. ---------------------------------------- Feature #21028: Method for finding why an object isn't Ractor shareable https://bugs.ruby-lang.org/issues/21028#change-114168 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * Assignee: tenderlovemaking (Aaron Patterson) ---------------------------------------- `Ractor.shareable?` is easy to use, but if it returns false I would like to be able to figure out what object is causing the data structure to _not_ be Ractor shareable. The context is that I'm trying to make some complex data structures in Rails deeply frozen. If they are deeply frozen they _should_ be Ractor shareable, but `Ractor.shareable?` is returning `false` and it's hard for me to figure out _why_. I would like a method that would either return all unshareable references, or a method that takes a block and unshareable references are yielded to the block. A method like `Ractor.unshareable_references?` or maybe `Ractor.shareable?(obj) { |not_shareable_obj| }` would be very helpful for discovering why an object is not shareable. Thanks! -- https://bugs.ruby-lang.org/
participants (4)
-
luke-gru (Luke Gruber)
-
mame (Yusuke Endoh)
-
osyoyu (Daisuke Aritomo)
-
tenderlovemaking (Aaron Patterson)