Project

General

Profile

Actions

Feature #19362

closed

#dup on Proc doesn't call initialize_dup

Added by zverok (Victor Shepelev) about 1 year ago. Updated 4 months ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:111953]

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) about 1 year ago

While String.allocate and Array.allocate are defined, Proc.allocate is not.
What do you expect as self of Proc#initialize_dup?

Actions #2

Updated by nobu (Nobuyoshi Nakada) about 1 year ago

  • Status changed from Open to Feedback

Updated by zverok (Victor Shepelev) about 1 year 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 zverok (Victor Shepelev) about 1 year 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) about 1 year ago

I'm not sure if this is a bug or intentional.
Please add this to [Misc #19429].

Updated by matz (Yukihiro Matsumoto) 12 months 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) 4 months ago

I've forgot this, but isn't this a feature require but not a bug?

Actions #9

Updated by nobu (Nobuyoshi Nakada) 4 months ago

  • Tracker changed from Bug to Feature
  • Backport deleted (2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN)
Actions #10

Updated by nobu (Nobuyoshi Nakada) 4 months ago

  • Status changed from Open to Closed

Applied in changeset git|1507118f0b70fc8002b4b0f186b464c64965cd1e.


[Feature #19362] Call #initialize_dup hook at Proc#dup

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like1Like0Like0Like0Like0