Bug #14266
closedSet#clone(freeze: false) makes frozen internal hash
Description
% irb -r irb/completion --simple-prompt
>> require 'set'
=> true
>> set=Set[].freeze.clone(freeze: false)
=> #<Set: {}>
>> set.frozen?
=> false
>> set.instance_variable_get(:@hash).frozen?
=> true
In Set#initialize_clone, clone hash without freeze keyword argument.
But I think there is no easy way how to know freeze keyword argument value in initialize_clone.
# Clone internal hash.
def initialize_clone(orig)
super
@hash = orig.instance_variable_get(:@hash).clone
end
Updated by jeremyevans0 (Jeremy Evans) almost 8 years ago
I see two possible ways to fix this:
-
Switch to overriding
cloneinstead ofinitialize_clonein such cases. -
Make
clone(freeze: false)callinitialize_clone(freeze: false), but havecloneotherwise callinitialize_clonewithout a keyword argument. MakeObject#initialize_cloneaccept and ignore thefreezekeyword. This way, if you overrideinitialize_cloneand don't have it accept thefreezekeyword,clone(freeze: false)will raise an ArgumentError. That's probably better than returning a unfrozen object with frozen instance variables.
Updated by znz (Kazuhiro NISHIYAMA) almost 8 years ago
- Assignee set to knu (Akinori MUSHA)
Updated by jeremyevans0 (Jeremy Evans) about 6 years ago
- Related to Feature #16129: Call initialize_clone with freeze: false if clone called with freeze: false added
Updated by jeremyevans (Jeremy Evans) almost 6 years ago
- Status changed from Open to Closed
Applied in changeset git|04eb7c7e462d1fcbab9efc7022c1b43636ab878a.
Call initialize_clone with freeze: false if clone called with freeze: false
This makes it possible to initialize_clone to correctly not freeze
internal state if the freeze: false keyword is passed to clone.
If clone is called with freeze: true or no keyword, do not pass
a second argument to initialize_clone to keep backwards
compatibility.
This makes it so that external libraries that override
initialize_clone but do not support the freeze keyword will fail
with ArgumentError if passing freeze: false to clone. I think that
is better than the current behavior, which succeeds but results in
an unfrozen object with frozen internals.
Fix related issues in set and delegate in stdlib.
Fixes [Bug #14266]