Project

General

Profile

Feature #17273

Updated by ko1 (Koichi Sasada) about 1 year 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 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

Back