Bug #8078
closed
Once nil is frozen, an unfrozen instance cannot be reached
Added by mhuggins (Matt Huggins) about 11 years ago.
Updated about 11 years ago.
Description
=begin
This is a rather peculiar bug I stumbled across. The basic issue is that once nil
has been frozen, there is no way to access an unfrozen instance of nil.
nil.frozen? => false
nil.freeze
nil.frozen? => true
I say this is a peculiar bug because generally it doesn't matter if nil
is frozen or not (since it is basically frozen even if not explicitly defined as such). However, since Ruby is based upon duck typing, you might run into a scenario like the following:
def get(cache_key)
content = Rails.cache.read(cache_key)
content.frozen? ? content.dup : content
end
If I call the above method and the cache key exists, content
is a frozen string, which I then dup
to get an unfrozen copy. If I call the above method and the cache key does NOT exist, content
is a frozen nil
, which it then attempts to dup
unsuccessfully since a NilClass instance cannot be duped.
=end
- Status changed from Open to Rejected
nil is an immediate. There are no multiple nils; nil.object_id is a constant. Same as true & false.
Any code that checks for frozen?
and then does a dup might have problems with any Ruby immediate. Note that fixnums & floats are frozen in Ruby 2.0.0. There is duplicable?
in activesupport for that reason.
This is a rather peculiar bug I stumbled across. The basic issue is that once nil
has been frozen, there is no way to access an unfrozen instance of nil.
nil.frozen? => false
nil.freeze
nil.frozen? => true
I say this is a peculiar bug because generally it doesn't matter if nil
is frozen or not (since it is basically frozen even if not explicitly defined as such). However, since Ruby is based upon duck typing, you might run into a scenario like the following:
def get(cache_key)
content = Rails.cache.read(cache_key)
content.frozen? ? content.dup : content
end
If I call the above method and the cache key exists, content
is a frozen string, which I then dup
to get an unfrozen copy. If I call the above method and the cache key does NOT exist, content
is a frozen nil
, which it then attempts to dup
unsuccessfully since a NilClass instance cannot be duped.
Hmm...
I don't think nil is mutable logically. Why can't we make nil is frozen at beginning?
kosaki (Motohiro KOSAKI) wrote:
I don't think nil is mutable logically. Why can't we make nil is frozen at beginning?
I can't see a really good use for it, but nil
can have attributes and is mutable.
Up to Ruby 2.0, the same was true for Fixnum, Bignum and Floats. But flonum optimization made it uncertain if a float was an immediate or not (e.g. 1.0 is an immediate in Ruby 2.0.0 on 64 bit platforms, but not if 32 bit). So it was decided to freeze them all, to avoid platform dependence. Since the same reasoning applied to Fixnum vs Bignum (e.g. 1<<42 is a Bignum on 32 bit platforms, so not an immediate, but is a Fixnum and thus an immediate on 64 bits), it was judged safer to freeze fixnums & bignums too.
On the other hand, nil
is always the same immediate, so there is no danger in leaving it unfrozen.
Also available in: Atom
PDF
Like0
Like0Like0Like0