How to create an Object who act as a False in Ruby
Unfortunately, this is not possible.
This is one of those annoying cases where Ruby is not object-oriented. In OO, it must be possible for one object to simulate another (in fact, depending on whom you ask, this is the very definition of OO – remember that OO came out of simulation), but it is not possible to build an object which simulates false
.
This is because, in Ruby, conditional control structures are baked into the language and don't translate into message sends, whereas in other OO languages they are just regular message sends (or at least translate into message sends, just like for
in Ruby translates into each
). For example, in Smalltalk, Booleans are actually implemented using the Church encoding of Booleans you know from Lambda Calculus, and translated to Ruby they look a bit like this:
class FalseClass
def if(&block)
# do nothing
end
def if_then_else(then_lambda, else_lambda)
else_lambda.()
end
def not
true
end
def and(&block)
self
end
def or(&block)
block.()
end
end
And TrueClass
is just the mirror image:
class TrueClass
def if(&block)
block.()
end
def if_then_else(then_lambda, else_lambda)
then_lambda.()
end
def not
false
end
def and(&block)
block.()
end
def or(&block)
self
end
end
And then, instead of something like
if 2 < 3 then foo end
if 2 < 3 then bar else baz end
You would have
(2 < 3).if { foo }
(2 < 3).if_then_else(-> { bar }, -> { baz })
# using the new keyword arguments in Ruby 2.0, it almost reads like Smalltalk:
class FalseClass
def if(then: -> {}, else: -> {})
else.()
end
end
class TrueClass
def if(then: -> {}, else: -> {})
then.()
end
end
(2 < 3).if(then: -> { bar }, else: { baz })
That way, you can easily create an object which simulates false
simply by implementing the respective methods.
In other cases, where some object really absolutely must be an instance of a specific class and not just speak the correct protocol, Ruby provides an escape hatch. For example, if a method really requires an Array
as an argument, then it will first try to call to_ary
to at least give you a chance to convert your object into an Array
. The same goes for to_str
, to_int
, to_proc
, to_float
etc. But there is no equivalent to_bool
protocol.
Return true/false on creation of object
You could try
@object = Blah.create()
@object.persisted? # true or false
also if you want to throw an error instead you could use the bang version, be sure to use rescue
@object = Blah.create!()
Ruby's 'is_a?' is returning false for built-in types, what's happening?
I wrote another answer, but one major question is - why are you doing this? Why not, instead, just call flatten
on the array so you just get the entries? Or, check for the behavior of the objects instead. You might need to give more detail about what you require.
Ruby nil-like object
This is a pretty long answer with a bunch of ideas and code samples of how to approach the problem.
try
Rails has a try method that let's you program like that. This is kind of how it's implemented:
class Object
def try(*args, &b)
__send__(*a, &b)
end
end
class NilClass # NilClass is the class of the nil singleton object
def try(*args)
nil
end
end
You can program with it like this:
fizz.try(:buzz).try(:foo).try(:bar)
You could conceivably modify this to work a little differently to support a more elegant API:
class Object
def try(*args)
if args.length > 0
method = args.shift # get the first method
__send__(method).try(*args) # Call `try` recursively on the result method
else
self # No more methods in chain return result
end
end
end
# And keep NilClass same as above
Then you could do:
fizz.try(:buzz, :foo, :bar)
andand
andand uses a more nefarious technique, hacking the fact that you can't directly instantiate NilClass subclasses:
class Object
def andand
if self
self
else # this branch is chosen if `self.nil? or self == false`
Mock.new(self) # might want to modify if you have useful methods on false
end
end
end
class Mock < BasicObject
def initialize(me)
super()
@me = me
end
def method_missing(*args) # if any method is called return the original object
@me
end
end
This allows you to program this way:
fizz.andand.buzz.andand.foo.andand.bar
Combine with some fancy rewriting
Again you could expand on this technique:
class Object
def method_missing(m, *args, &blk) # `m` is the name of the method
if m[0] == '_' and respond_to? m[1..-1] # if it starts with '_' and the object
Mock.new(self.send(m[1..-1])) # responds to the rest wrap it.
else # otherwise throw exception or use
super # object specific method_missing
end
end
end
class Mock < BasicObject
def initialize(me)
super()
@me = me
end
def method_missing(m, *args, &blk)
if m[-1] == '_' # If method ends with '_'
# If @me isn't nil call m without final '_' and return its result.
# If @me is nil then return `nil`.
@me.send(m[0...-1], *args, &blk) if @me
else
@me = @me.send(m, *args, &blk) if @me # Otherwise call method on `@me` and
self # store result then return mock.
end
end
end
To explain what's going on: when you call an underscored method you trigger mock mode, the result of _meth
is wrapped automatically in a Mock
object. Anytime you call a method on that mock it checks whether its not holding a nil
and then forwards your method to that object (here stored in the @me
variable). The mock then replaces the original object with the result of your function call. When you call meth_
it ends mock mode and returns the actual return value of meth
.
This allows for an api like this (I used underscores, but you could use really anything):
fizz._buzz.foo.bum.yum.bar_
Brutal monkey-patching approach
This is really quite nasty, but it allows for an elegant API and doesn't necessarily screw up error reporting in your whole app:
class NilClass
attr_accessor :complain
def method_missing(*args)
if @complain
super
else
self
end
end
end
nil.complain = true
Use like this:
nil.complain = false
fizz.buzz.foo.bar
nil.complain = true
Why do Ruby object_ids for true, false, and nil seem to differ in Windows vs. Ubuntu?
As the accepted answer on the question you linked to says, 0, 20, and 8 are the Object IDs that are used when using flonums on YARV.
So, obviously, your Windows implementation is not using flonums. The most likely reason is that either you are not using YARV (e.g. using JRuby or Rubinius), or you are using YARV, but a 32 bit version.
Note: Object IDs are a private internal implementation detail of the particular Ruby implementation. The version of Ruby you are using is completely irrelevant. What is relevant is which implementation you are using, which version, which commandline options, how you compiled it, what your environment is and so on. It has nothing to do with the language.
Note also: you should never ever rely on the specific value of Object IDs. Object IDs guarantee two things, and only these two things:
- An object does not change its Object ID during its lifetime.
- No two objects have the same Object ID at the same time.
Here are some things that are not guaranteed:
- It is not guaranteed that an object will have the same Object ID during different runs of the program.
- It is not guaranteed that an Object ID is unique during the runtime of the program, it may be re-used for different objects as long as those objects don't live at the same time.
- It is not guaranteed that the Object ID will follow a certain pattern, e.g. that it is always the memory address of the object (not true on JRuby, for example) or that it is always a specific value (not true for
nil
andfalse
, as you have just discovered), or that it is always related to the object's value in some way (due to the specific way that YARV optimizesInteger
s, the Object ID for small integers will always be 2n+1, but that is only true for small integers (where the definition of "small" depends on whether you run a 64 bit or 32 bit version of YARV) and it is only an implementation detail that may change at any moment without notice).
How does Ruby evaluate the class of an object when evaluating the truthiness in a condition?
There are only two objects which evaluate falsy. Ruby simply checks whether the object is one of those two. Period.
Note that one of the foundations of OO is simulation: an object can simulate another object. This is not true here: it is impossible to simulate nil
or false
. This is one of those annoying cases where Ruby violates OO, very similar to Object#equal?
.
What evaluates to false in Ruby?
false
and nil
are the only ones:
http://www.ruby-doc.org/core-2.1.1/FalseClass.html
Rails provides present?
which also includes empty strings and empty arrays: http://api.rubyonrails.org/classes/Object.html#method-i-present-3F
Related Topics
Read and Write Yaml Files Without Destroying Anchors and Aliases
Ruby: Class Instance Variables VS Instance Variables
Setspeed in Selenium Webdriver Using Ruby
How to Use the Debugger with Ruby 2.0
The Class/Object Paradox Confusion
Installing Rvm (Ruby Version Manager)
Google Plus API Shutdown Today, Which Alternative Can Be Used to Authentication
How to Add an Array to Another Array in Ruby and Not End Up With a Multi-Dimensional Result
How to Do Relative Time in Rails
Rufus Scheduler Not Running in Production
Libmysqlclient.So.15: Cannot Open Shared Object File: No Such File or Directory
Paperclip::Errors::Missingrequired
validatorerror With Rails 4
Uninstalling All Gems Ruby 2.0.0
Rails: an Elegant Way to Display a Message When There Are No Elements in Database