Project

General

Profile

Bug #11929

No programatic way to check ability to dup/clone an object

Added by lkdjiin (xavier nayrac) almost 4 years ago. Updated almost 3 years ago.

Status:
Closed
Priority:
Normal
Target version:
-
ruby -v:
ruby 2.3.0dev (2015-12-06 trunk 52904) [i686-linux]
[ruby-core:72621]

Description

We can't dup a Fixnum, and it's ok. But I'm wondering «why is Fixnum saying it can dup?»

1.respond_to?(:dup) #=> true

Don't you think that the dup method should be undefined in the class Fixnum?

Currently I can do class Fixnum; undef :dup; end, but that should be in the core Ruby, isn't it?


Related issues

Related to Ruby master - Feature #12979: Avoid exception for #dup on Integer (and similar cases)ClosedActions

History

Updated by 0x0dea (D.E. Akers) almost 4 years ago

This demonstration should clarify the observed behavior. Symbol, Fixnum, and indeed every other numeric class inherit their #dup from Kernel, whose implementation does a sanity check before proceeding, thus obviating the need to remove the method from the classes for which it might otherwise make sense to do so.

Updated by MikeVastola (Mike Vastola) about 3 years ago

  • Subject changed from dup should be undefined in Fixnum to No programatic way to check ability to dup/clone an object

D.E., while you're technically not wrong, IMHO, the need to undef the method is only abated in the strictest of senses: the sanity check averts what might otherwise be a segfault or memory leak or some other aberration, and makes things 'safe', but it's neither straightforward nor intuitive for the programmer, nor consistent with the implementation of similar functions in ruby.

For instance, freeze doesn't throw any sort of similar error when you call it on an already frozen object, or even for the immediate (and therefore inherently immutable) objects you used in your demonstration.

I think the core issue Xavier is getting at here (and I took the liberty of updating the subject thusly; Xavier, if you don't feel it's a fair representation of the issue, please feel free to change it back) is that a select few object types in Ruby are immediate variables and therefore cannot be duped/cloned, yet there is no graceful/robust method of averting the error thrown by this sanity check when you attempt to dup/clone them. (In the source, both rb_obj_dup and rb_obj_clone if the object to be duped/cloned is a rb_special_const_p. As far as I can tell, this method nor anything equivalent is exposed in the ruby language, however.)

I literally can't imagine any scenario in which a dev, when, say, coding a class with the line:

return val.dup.freeze

.. really wants an Exception thrown when val happens to be de-facto un-dup-able. What they really want is:

return val.dup.freeze rescue val

To me it seems there are three possible solutions to this (of which any two can be implemented):

  • As Xavier suggested, only define the functions for objects that will actually dup/clone. (This will implicitly allow respond_to? checks as well as not interfere with existing code that may attempt to rescue failed attempts -- that is unless TypeError was specified, and even that could be worked around with a bit more code.)
  • Add additional methods to all objects named dupable? and clonable? that return values consistent with exactly what their names suggest.
  • Have these methods function exactly the way freeze does: fail silently. If the object can't be duped/cloned because it's an immediate, dup/clone should return the object itself. (There shouldn't be any harm in doing so since nothing about the object can be changed in the first place.)

Updated by duerst (Martin Dürst) about 3 years ago

  • Assignee set to matz (Yukihiro Matsumoto)

I clearly prefer the last proposal (fail silently).

That would make for a much more unified, streamlined protocol, avoiding needless exposition of internals. It would do exactly what dup (and clone) are described to do, namely (pretend to) return a shallow copy.

Updated by Eregon (Benoit Daloze) about 3 years ago

Martin Dürst wrote:

I clearly prefer the last proposal (fail silently).

That would make for a much more unified, streamlined protocol, avoiding needless exposition of internals. It would do exactly what dup (and clone) are described to do, namely (pretend to) return a shallow copy.

I very much agree.

Updated by lkdjiin (xavier nayrac) about 3 years ago

Mike, your last proposal is simple, beautiful and smart.

1.dup #=> 1

Updated by matz (Yukihiro Matsumoto) almost 3 years ago

  • Status changed from Open to Feedback
  1. ability to be duped cannot be checked by respond_to?. It's simply wrong.
  2. the "fail silently" proposal is attractive, but it should be a separate proposal (for the sake of bookkeeping).

Matz.

#7

Updated by duerst (Martin Dürst) almost 3 years ago

  • Related to Feature #12979: Avoid exception for #dup on Integer (and similar cases) added

Updated by matz (Yukihiro Matsumoto) almost 3 years ago

  • Status changed from Feedback to Closed

The issue closed by #12979

Matz.

Also available in: Atom PDF