Bug #14719
closedFalseClass wrapped in a SimpleDelegator evaluates to true in an IF statement
Description
Hi, thanks for Ruby :-)
I have run into a problem. When I wrap the boolean false in a SimpleDelegator it breaks the semantics of the boolean when evaluated in expressions such as IF statements - returning true when I would have expected false.
Here is a test case...
class BoldBool < SimpleDelegator
end
false_bool = BoldBool.new(false)
if false_bool
puts "I'm evaluated as true but I should be false."
end
When I run it I get:
#=>I'm evaluated as true but I should be false.
Expected result:
No output.
I understand that there may be good reasons for why this is happening (eg. the class of the object false_bool may be a BoldBool and this is not a FalseClass) however it breaks the fundamental semantics of a boolean - in which case I think we should consider raising an ArgumentError in the Ruby language if a Boolean is passed to the constructor of a SimpleDelegator.
I tried to workaround the problem by overriding equals?(). I am guessing that this would be the correct approach - and that this is what is used by the IF expression to determine whether it is dealing with a truthy object or a falsey...
class BoldBool < SimpleDelegator
def equal?(obj)
if __getobj__.is_a? FalseClass and obj == false
return true
else
__getobj__.equal?(obj)
end
end
end
false_bool = BoldBool.new(false)
if false_bool
puts "I'm evaluated as true but I should be false."
end
However this gives me the error...
/home/me/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/delegate.rb:313:in `__getobj__': not delegated (ArgumentError)
from simple_delegator_on_boolean_with_equals_override.rb:5:in `equal?'
from /home/me/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/delegate.rb:333:in `__setobj__'
from /home/me/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/delegate.rb:72:in `initialize'
from simple_delegator_on_boolean_with_equals_override.rb:13:in `new'
from simple_delegator_on_boolean_with_equals_override.rb:13:in `<main>'
If I try an even simpler override approach as an experiment this errors too...
class BoldBool < SimpleDelegator
def equal?(obj)
true
end
end
false_bool = BoldBool.new(false)
if false_bool
puts "I'm evaluated as true but I should be false."
end
... with the error...
/home/me/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/delegate.rb:333:in `__setobj__': cannot delegate to self (ArgumentError)
from /home/me/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/delegate.rb:72:in `initialize'
from simple_delegator_on_boolean_with_simple_equals_override.rb:9:in `new'
from simple_delegator_on_boolean_with_simple_equals_override.rb:9:in `<main>'
Is this SimpleDelegator behaviour a bug? (downloadable files attached containing the above snippets).
Files
Updated by marcandre (Marc-Andre Lafortune) over 6 years ago
- Status changed from Open to Rejected
I'm afraid you can not achieve what you want to achieve in Ruby. The only two objects that are falsy in Ruby are nil
and false
. No other object can "look" like false
. This is by design and can not be changed.
Updated by theirishpenguin (Declan McGrath) over 6 years ago
Thanks Marc-Andre. Appreciate the quick response.
Updated by theirishpenguin (Declan McGrath) over 6 years ago
- Subject changed from FalseClass wrapping a SimpleDelegator evaluates to true in an IF statement to FalseClass wrapped in a SimpleDelegator evaluates to true in an IF statement