From: ko1@...
Date: 2020-10-29T19:47:27+00:00
Subject: [ruby-core:100657] [Ruby master Feature#17273]	shareable_constant_value pragma

Issue #17273 has been updated by ko1 (Koichi Sasada).


Eregon (Benoit Daloze) wrote in #note-16:
> I guess it's relatively rare that a gem would (intentionally) expose a non-frozen constant as part of its API, and that the gem relies on being able to mutate it.

To confirm it, we will introduce experimental radical API.
Other verification methods are welcome.

----------------------------------------
Feature #17273: shareable_constant_value pragma
https://bugs.ruby-lang.org/issues/17273#change-88297

* Author: ko1 (Koichi Sasada)
* Status: Open
* Priority: Normal
----------------------------------------
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 freezing objects deeply (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
```

The effect of this pragma is closed to the scope.

```ruby
class C
  # shareable_constant_value: true
  A = 'str'
  p A.frozen? #=> true

  1.times do
    # shareable_constant_value: false
    B = 'str'
    p B.frozen? #=> false
  end
end

X = 'str'
p X.frozen? #=> false
```

`Ractor.make_shareable(obj)` doesn't affect anything to 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



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>