Project

General

Profile

Feature #18035

Updated by ioquatix (Samuel Williams) 11 months ago

It would be good to establish some rules around mutability, immutability, frozen, and deep frozen in Ruby. 

 I see time and time again, incorrect assumptions about how this works in production code. Constants that aren't really constant, people using `#freeze` incorrectly, etc. 

 I don't have any particular preference but: 

 - We should establish consistent patterns where possible, e.g. 
   - Objects created by `new` are mutable. 
   - Objects created by literal are immutable. 

 We have problems with how `freeze` works on composite data types, e.g. `Hash#freeze` does not impact children keys/values, same for Array. Do we need to introduce `freeze(true)` or `#deep_freeze` or some other method? 

 Because of this, frozen does not necessarily correspond to immutable. This is an issue which causes real world problems. 

 I also propose to codify this where possible, in terms of "this class of object is immutable" should be enforced by the language/runtime, e.g. 


 ```ruby 
 module Immutable 
   def new(...) 
     super.freeze 
   end 
 end 

 class MyImmutableObject 
   extend Immutable 

   def initialize(x) 
     @x = x 
   end 
  
   def freeze 
     return self if frozen? 
    
     @x.freeze 
    
     super 
   end 
 end 

 o = MyImmutableObject.new([1, 2, 3]) 
 puts o.frozen? 
 ``` 

 Finally, this area has an impact to thread and fiber safe programming, so it is becoming more relevant and I believe that the current approach which is rather adhoc is insufficient. 

 I know that it's non-trivial to retrofit existing code, but maybe it can be done via magic comment, etc, which we already did for frozen string literals. 

 Proposed PR: https://github.com/ruby/ruby/pull/4879

Back