Feature #17273
Updated by ko1 (Koichi Sasada) about 5 years ago
This proposal is to introduce `# shareable_constant_value: true` pragma to make constant values shareable objects.
With this pragma, you don't need to add `freeze` to access from non-main ractors.
```ruby
# shareable_constant_value: true
A = [1, [2, [3, 4]]]
H = {a: "a"}
Ractor.new do
p A
p H
end.take
```
## Background
Now, we can not access constants which contains a unshareable object from the non-main Ractor.
```ruby
A = [1, [2, [3, 4]]]
H = {a: "a"}
Ractor.new do
p A #=> can not access non-sharable objects in constant Object::A by non-main Ractor. (NameError)
p H
end.take
```
If we know we don't modify `A` and `H` is frozen object, we can freeze them, and other ractors can access them.
```ruby
A = [1, [2, [3, 4].freeze].freeze].freeze
H = {a: "a".freeze}.freeze
Ractor.new do
p A #=> [1, [2, [3, 4]]]
p H #=> {:a=>"a"}
end.take
```
Adding nesting data structure, we need many `.freeze` method.
Recently, I added `Ractor.make_shareable(obj)` makes `obj` shareable with depply freezing objects deeply object (see [Feature #17274]).
We only need to introduce this method for each constant.
```ruby
A = Ractor.make_shareable( [1, [2, [3, 4]]] )
H = Ractor.make_shareable( {a: "a"} )
Ractor.new do
p A #=> [1, [2, [3, 4]]]
p H #=> {:a=>"a"}
end.take
```
However, if we have 100 constants, it is troublesome.
## Proposal
With `# shareable_constant_value: true`, you can specify all constants are shareable.
```ruby
# shareable_constant_value: true
A = [1, [2, [3, 4]]]
# compiled with: A = Ractor.make_shareable( [1, [2, [3, 4]]] )
H = {a: "a"}
# compiled with: H = Ractor.make_shareable( {a: "a"} )
Ractor.new do
p A
p H
end.take
```
(Strictly speaking, don't call `Ractor.make_shareable`, but apply same effect. This means rewriting `Ractor.make_shareable` doesn't affect this behavior)
You can specify `# shareable_constant_value: false` in the middle of the place.
```ruby
# shareable_constant_value: true
S1 = 'str' #
p S1.frozen? #=> true
# shareable_constant_value: false
S2 = 'str' #
p S2.frozen? #=> false
```
`Ractor.make_shareable(obj)` doesn't affect shareable objects.
```ruby
# shareable_constant_value: true
class C; end
D = C
p D.frozen? #=> false
```
Some objects can not become shareable objects, so it raises an exception:
```ruby
# shareable_constant_value: true
T = Thread.new{}
#=> `make_shareable': can not make shareable object for #<Thread:0x000055952e40ffb0 /home/ko1/ruby/src/trunk/test.rb:3 run> (Ractor::Error)
```
## Implementation
https://github.com/ruby/ruby/pull/3681/files