Issue #12979 has been updated by Mike Vastola.


Nobuyoshi Nakada wrote:
> Should `Kernel#clone` be same?

The original consensus was that the fix should be for both **`#dup`** and **`#clone`** to fail silently on immediate objects. The person who created this issue rendered **`#clone`** as "and similar cases" in the title, perhaps assuming there could be additional places changes were necessary?

Nobuyoshi Nakada wrote:
> I remember `clone` has `freeze` option.
> What should `1.clone(freeze: false)` do, ignore the option, or raise an `ArgumentError`?

This is totally beside the point. Look at it this way:
**`1.clone(freeze: false)`**  **`1.clone`**
**`1.clone(freeze: true)`**  **`1.clone.freeze`**

_(NB: I'm not familiar with this particular invocation of **`#clone`**, so it's possible this argument to the method is supposed to do some sort of deep **`#freeze`**, but since we're dealing only with immediates here, this simplification can suffice.)_

In the first line, the hash argument might as well be absent, as not freezing is the default behavior. 
In the second line, you're attempting to freeze an immediate, which -- contrary to Matz's statement -- aren't unfreezable, but in fact ***always*** frozen. As a result, the **`#freeze`** instruction here is also silently ignored.

This entire issue is about **`#dup`**/**`#clone`**. In fact, if you read the parent issue, a major reason why the current behavior is so unintuitive is precisely because **`#freeze`** fails silently and returns the object unmodified, but the former two methods do not.

----------------------------------------
Feature #12979: Avoid exception for #dup on Integer (and similar cases)
https://bugs.ruby-lang.org/issues/12979#change-61795

* Author: Martin Drst
* Status: Open
* Priority: Normal
* Assignee: Nobuyoshi Nakada
----------------------------------------
This is a proposal resulting from a discussion in Bug #11929. Because this is proposing a different solution from #11929, it has a new number.

#11929 shows that people are confused that e.g. 3.dup throws an exception (but Integer#dup is actually implemented, so Integer.respond_to? :dup => true).

Integer#dup should fail silently, returning the receiver, in the same way as Integer#freeze fails silently. Citing from #11929 (comment by Mike Vastola): "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.)". Citing some more:

> 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

The proposal also has the advantage that it leads to 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.



-- 
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>