Misc #13634


NilClass is lying about respond_to?(:clone)

Added by rovf (Ronald Fischer) over 4 years ago. Updated over 4 years ago.



I put this under "Misc", because I'm not sure, whether this is a bug, a feature request, or maybe a deliberate (but for me obscure) decision in language design:

NilClass (and Fixnum) do not support clone. That's fine. However,

nil.respons_to?(:clone) returns true.

This means that we can ask nil to clone itself (we don't get a NoMethod error), it's just trying to do so throws an exception.

I stumbled over this problem when I had an collection of objects of different types, and wanted to apply :clone to some of them. My code went approximately like this:

object = collection[key]
return object.respond_to?(:clone) ? object.clone : object

This doesn't work, if object is nil, true, false, a Symbol or a Fixnum, because all of them claim to respond to :clone.

Of course, there is a trivial workaround (I just have to rescue the exception), but I find this language design not really intuitive. I think there are two possibilites, how this can be made better:

(1) If we decide, that nil is not clonable (because there can be only one nil), then respond_to?(:clone) should IMHO simply be false.

(2) However, there might be even be a reason why :clone should be applicable. Note that the usual semantics of clone is to do a shallow copy (for instance, when we 'clone' a nested array). If we want to have a deep copy, the usual approach is Marshal.load(Marshal.dump(object)). Now the odd thing is that we can not "shallowly copy" nil, i.e. nil.clone is forbidden, but we can do a deep copy, i.e. Marshal.load(Marshal.dump(nil)) works. So, an alternative would be to have nil.clone simply return the identical object.

Both (1) seems to me a sound solution. The solution (2) has the drawback that we can't guarantee anymore that x.clone has a different object id than x, but is probably the behaviour a programmer would intuitively expect.


Also available in: Atom PDF