Feature #19362
closed#dup on Proc doesn't call initialize_dup
Description
In #17545, #dup had changed to create an instance of the subclass.
It, though, doesn't invoke initialize_dup of the subclass, unlike other standard classes.
class MyAry < Array def initialize_dup(...) p(self.class, ...) super end end class MyString < String def initialize_dup(...) p(self.class, ...) super end end class MyProc < Proc def initialize_dup(...) p(self.class, ...) super end end MyString.new('test').dup # prints MyString, "test" MyAry.new(['test']).dup # prints MyAry, ["test"] MyProc.new { 'test' }.dup # doesn't print anything This makes the change in #17545 useless: while inheriting from core classes is indeed marginal, one of author's intention might be carrying additional information with the Proc instance, and bypassing #initialize_dup makes it impossible to maintain this information.
It seems that actually #initialize_dup is also invoked on the core classes themselves, but ignored on Proc.
class Array def initialize_dup(...) p(self.class, ...) super end end class String def initialize_dup(...) p(self.class, ...) super end end class Proc def initialize_dup(...) p(self.class, ...) super end end 'test'.dup # prints String, "test" ['test'].dup # prints Array, ["test"] Proc.new { 'test' }.dup # doesn't print anything Which is an even more marginal problem but still an inconsistency.
Updated by nobu (Nobuyoshi Nakada) almost 3 years ago
While String.allocate and Array.allocate are defined, Proc.allocate is not.
What do you expect as self of Proc#initialize_dup?
Updated by nobu (Nobuyoshi Nakada) almost 3 years ago
- Status changed from Open to Feedback
Updated by zverok (Victor Shepelev) almost 3 years ago
What do you expect as self of
Proc#initialize_dup?
@nobu (Nobuyoshi Nakada) "the current proc object", like in any initialize[...]. I am not sure I understand why is it impossible. From layman's point of view, those two should work the same way:
class TaggedString < String attr_reader :tag def initialize(val, tag:) super(val) @tag = tag end def initialize_dup(other) super @tag = other.tag end end class TaggedProc < Proc attr_reader :tag def initialize(tag, &block) super(&block) @tag = tag end def initialize_dup(other) super @tag = other.tag end end s = TaggedString.new('test', tag: 'foo') p s.tag #=> 'foo' p s.dup.tag #=> 'foo' t = TaggedProc.new('test') { } p t.tag #=> 'test' p t.dup.tag #=> expected 'test', got nil Otherwise, I am not sure what's the semantics of Proc#dup and how it is supposed to be used.
And if it isn't supposed to, it might make sense to prohibit its usage or at least document the quirks?..
Updated by nobu (Nobuyoshi Nakada) almost 3 years ago
- Status changed from Feedback to Open
Updated by zverok (Victor Shepelev) almost 3 years ago
@nobu (Nobuyoshi Nakada) Thanks! Will this PR be merged? (I secretly hoped to have it in 3.2.1 :)))
Updated by nobu (Nobuyoshi Nakada) almost 3 years ago
I'm not sure if this is a bug or intentional.
Please add this to [Misc #19429].
Updated by matz (Yukihiro Matsumoto) over 2 years ago
Accepted, mostly for the sake of consistency. As a general suggestion, making subclasses from built-in classes is not a good idea in Ruby, though.
Matz.
Updated by nobu (Nobuyoshi Nakada) about 2 years ago
I've forgot this, but isn't this a feature require but not a bug?
Updated by nobu (Nobuyoshi Nakada) about 2 years ago
- Tracker changed from Bug to Feature
- Backport deleted (
2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN)
Updated by nobu (Nobuyoshi Nakada) about 2 years ago
- Status changed from Open to Closed
Applied in changeset git|1507118f0b70fc8002b4b0f186b464c64965cd1e.
[Feature #19362] Call #initialize_dup hook at Proc#dup