Project

General

Profile

Actions

Feature #21028

open

Method for finding why an object isn't Ractor shareable

Added by tenderlovemaking (Aaron Patterson) about 1 month ago. Updated 9 days ago.

Status:
Open
Target version:
-
[ruby-core:120617]

Description

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!

Updated by tenderlovemaking (Aaron Patterson) about 1 month ago

  • Assignee set to tenderlovemaking (Aaron Patterson)

Updated by luke-gru (Luke Gruber) about 1 month ago

I suspect it's probably a Proc object. The feature sounds good to me, and wouldn't be hard to implement I think.

Updated by osyoyu (Daisuke Aritomo) 21 days ago

+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.

Updated by mame (Yusuke Endoh) 9 days ago

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.

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
Actions

Also available in: Atom PDF

Like1
Like0Like0Like0Like1