Feature #16601
openLet `nil.to_a` and `nil.to_h` return a fixed instance
Description
Now, nil.to_s
returns a fixed instance:
nil.to_s.object_id # => 440
nil.to_s.object_id # => 440
nil.to_s.object_id # => 440
...
This is useful when we have some variable foo
which may be either nil
or a string, and we want to check its emptiness in a condition:
if foo.to_s.empty?; ... end
By this feature, we do not (need to) create a new instance of an empty string each time we check foo
, even when it happens to be nil
.
There are similar situations with arrays and hashes. We may have variable bar
which may be either nil
or an array, or baz
which may be either nil
or a hash, and we want to check their emptiness in conditions as follows:
if bar.to_a.empty?; ... end
if baz.to_h.empty?; ... end
But unlike nil.to_s
, the methods nil.to_a
and nil.to_h
create new instances of empty array or hash each time they are called:
nil.to_a.object_id # => 540
nil.to_a.object_id # => 560
nil.to_a.object_id # => 580
...
nil.to_h.object_id # => 460
nil.to_h.object_id # => 480
nil.to_h.object_id # => 500
...
The fact that this is somewhat inefficient discourages the use of foo.to_a
or foo.to_h
in such use cases.
I request nil.to_a
to nil.to_h
to return a fixed empty instance.
Updated by shevegen (Robert A. Heiler) almost 5 years ago
I somewhat agree with the explanation, so I think the suggestion in itself is fine
as such.
I believe there may be a language design consideration, though, e. g. whether matz
thinks that this makes sense from a language-design point of view (see the other
explanation about the various attr* methods and why there is no attr* variant
that e. g. combines reader methods with a trailing '?' character).
Another smaller issue, if it is an issue, may be for ruby newcomers. For example,
say that a new user comes to ruby and asks about nil.to_a and nil.to_h
specifically - will there be an explanation somewhere? I am really just thinking
about the new-ruby-user situation in this regard, e. g. they may like to
understand why .to_a and .to_h may be special but not other .to* (if there
are any ... I don't even know how many exist for nil).
Note that these two points are not meaning that I am against the suggestion
at all - it is only meant to "carve out more details" from the proposal if
possible. :)
In my own code I usually check first for nil, before doing any further
checks, even "boolean checks" (if a variable is true or false). Not sure
if that is the best practice, different people write code differently,
but I sort of adopted that a long time ago. So I may not be the ideal
target audience either as I currently don't quite seem to do much on
nil, except actually I do indeed sometimes do .to_s, to ensure that
I have a string. This can indeed be a bit complicated sometimes, if
we have to distinguish between nil, string and a symbol. But I still
agree with your basic statement - it somewhat makes sense to me since
nil.to_a and nil.to_h will always "reproduce" the same result just
as .to_s would (and should, since it is nil).
Updated by byroot (Jean Boussier) almost 5 years ago
I'm not sure if nil.to_a
and nil.to_h
are actually frequent sources of allocations, but I agree with the general premise.
When profiling Ruby applications, it's frequent to see 30% of the time being spent in GC, which makes me think reducing useless allocations could lead to increased performance.
However as we've seen with trying to freeze the return of Symbol#to_s
[#16150] , there are some backward compatibility concerns.
So maybe the priority would be to implement [#16153] so that this kind of changes can go through a normal deprecation cycle.