From: ko1@... Date: 2020-10-19T20:48:03+00:00 Subject: [ruby-core:100429] [Ruby master Feature#17145] Ractor-aware `Object#deep_freeze` Issue #17145 has been updated by ko1 (Koichi Sasada). I implemented `Object#deep_freeze(skip_shareable: false)` for trial. https://github.com/ko1/ruby/pull/new/deep_freeze * It doesn't call `#freeze`, but only set frozen flag. * It set frozen bit for any objects such as Binding, Thread, and so on, but no effect other than adding ivars, etc. * Two pass freezing method * (1) collect reachable objects * (2) freeze collected objects This two pass strategy allows errors during collection phase (1). For example, if we introduce unable to "freeze" objects, we can stop collection and raise some error without any side-effect. However, if we call `#freeze`, we can't cancel intermediate state (some objects are frozen, some are not). I have no idea how to solve it, if we need to call `freeze` for each instance. `Object#deep_freeze(skip_shareable: true)` skips shareable objects to freeze. Maybe it is `ractor_freeze`, `shareable` and so on. I don't have strong opinion about this naming, but I try to unify with `Object#deep_freeze`. ---------------------------------------- Feature #17145: Ractor-aware `Object#deep_freeze` https://bugs.ruby-lang.org/issues/17145#change-88047 * Author: marcandre (Marc-Andre Lafortune) * Status: Open * Priority: Normal ---------------------------------------- I'd like to propose `Object#deep_freeze`: Freezes recursively the contents of the receiver (by calling `deep_freeze`) and then the receiver itself (by calling `freeze`). Values that are shareable via `Ractor` (e.g. classes) are never frozen this way. ```ruby # freezes recursively: ast = [:hash, [:pair, [:str, 'hello'], [:sym, :world]]].deep_freeze ast.dig(1, 1) # => [:str, 'hello'] ast.dig(1, 1).compact! # => FrozenError # does not freeze classes: [[String]].deep_freeze String.frozen? # => false # calls `freeze`: class Foo def freeze build_cache! puts "Ready for freeze" super end # ... end [[[Foo.new]]].deep_freeze # => Outputs "Ready for freeze" ``` I think a variant `deep_freeze!` that raises an exception if the result isn't Ractor-shareable would be useful too: ```ruby class Fire def freeze # do not call super end end x = [Fire.new] x.deep_freeze! # => "Could not be deeply-frozen: #<Fire:0x00007ff151994748>" ``` -- 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>