Reputation: 168209
Is there a method that tells if an object is mutable, similar to mutable?
in the following? If not, what is the best way to implement it?
"abcde".mutable? # => true
0.mutable? # => false
To answer mu is too short and dbenhur's question, I do not like the syntax of enumerated.inject(initial){...}
or enumerated.each_with_object(initial){...}
. I wanted a method that reverses the receiver and the argument, and I wanted it to be available to a wide variety of classes; so that I have:
initial.my_new_method(enumerated){...}
0.my_new_method(1..10){|sum, i| sum + i} # => 55
"a".my_new_method(b: 3, c: 4){|s, (k, v)| s + k.to_s * v} # => "abbbcccc"
This will make the return a modified version of the receiver, and is conceptually more natural. And with my_new_method
, I wanted it to be non destructive. When the receiver is mutable, I further wanted to define a destructive version
initial.my_new_method!(enumerated){...}
"a".my_new_method!(b: 3, c: 4){|s, (k, v)| s << k.to_s * v} # => "abbbcccc"
So to detect whether the receiver is mutable or not is necessary. It does not matter if it is frozen. If I use the destructive version of the method with a frozen object, it will simply raise an error. Nothing wrong with that.
Upvotes: 1
Views: 175
Reputation: 20398
There are two properties that can make an object immutable in ruby
1) the object may be frozen with Object#freeze
, in which case your immutability check is Object#frozen?
2) The object may be an immediate value. There's no built-in method I know of to tell that an object is immediate, so one must rely on a side-effect of the immediate nature. Immediate values are not permitted to have singleton-classes defined on them, so I might try the following as a proxy:
class Object
def immediate_value?
class <<self; end
return false
rescue TypeError
return true
end
def mutable?
!(frozen? || immediate_value?)
end
end
While this is probably a pretty reliable detector (I don't know of another mechanism that prevents opening the singleton class of an object), it does have the unfortunate side-effect of creating a singleton class for each object so queried.
Upvotes: 1
Reputation: 168209
I came up with this
class Object
def mutable?; !!(dup rescue false) end
end
Upvotes: -2
Reputation: 80085
AFAIK all (unfrozen) objects are mutable, except nil, true, false and all integers and symbols.
Upvotes: 2
Reputation: 61540
You can call .frozen?
on an object to see if that instance of an object is immutable:
1.9.3p194 :001 > a = Array.new
=> []
1.9.3p194 :002 > a.frozen?
=> false
1.9.3p194 :003 > a.freeze
=> []
1.9.3p194 :004 > a.frozen?
=> true
After calling .freeze
no other changes will be allowed on that instance of an Object, a RuntimeError
will be thrown if anyone attempts to change a frozen object.
EDIT:
As check mentions below in the comments 0.frozen?
will correctly return false
because 0 is an instance of the Fixnum
class.
Upvotes: 1