What is the meaning of `!!empty?`? - ruby

ActiveSupport extends Object with an instance method blank?:
class Object
def blank?
respond_to?(:empty?) ? !!empty? : !self
end
end
Could !!empty? be written as empty? instead? Is this a stylistic choice so that it reads easily as a method returning a boolean? Or is there something else?

The reason for this is that !! coerces the response from empty to a boolean. Empty can be defined differently on different objects so it is possible that someone in rails could have defined .empty? to not return a boolean. Since .blank? needs to return a boolean the !! is needed to ensure that a boolean is returned.

It is a common way to convert a truthy versus falesy value into strict true and false.

It is a common approach in Ruby to call !!(something). The result of the calculation will be boolean, not nil or something else:
!!(true) # true
!!(false) # false
!!(nil) # false

!! is used to force falsey/truthy values to false/true:
irb(main):001:0> !!nil == false
=> true

In fact, it used to be empty?. Here's the commit that changed it to !!empty?: https://github.com/rails/rails/commit/126dc47665c65cd129967cbd8a5926dddd0aa514
From the comments:
Bartuz:
Why double !! ? It returns the TrueClass / FalseClass anynway
fxn:
Because it is a dynamic language and subject to polymorphism, you just can't rely on empty? returning singletons, what you need to guarantee is that you return one no matter what.
The "improved" implementation however is incomplete, because you could just as well implement ! to return a non-boolean value:
class Foo
def !
nil
end
end
Foo.new.blank? #=> nil
To handle both methods (empty? and !), it should be implemented as:
!!(respond_to?(:empty?) ? empty? : !self)

Related

Ruby idiomatic way to return a boolean

Is there a more idiomatic way for me to return a boolean in #survey_completed?
This is how I did things in C#, and I have always felt that the last ternary clause to return false was redundant, so perhaps Ruby has a better way of doing this?
This is how what my code currently looks like:
def survey_completed?
self.survey_completed_at ? true: false
end
def survey_completed_at
# Seeing as the survey is submitted all or nothing, the time the last response is persisted
# is when the survey is completed
last_response = self.responses.last
if last_response
last_response.created_at
end
end
You can use double negation:
def survey_completed?
!!survey_completed_at
end
def survey_completed?
!survey_completed_at.nil?
end
The idiomatic way to do this in Ruby is to not do it. Every object except for false and nil evaluates to true in a Boolean context. Thus your survey_completed_at function already serves the purpose of the survey_completed? function.
If you got a response for the survey, last_response.created_at will be something non-nil thus the function will evaluate to true in a Boolean context. If you didn't get a response and last_response is nil, the if will evaluate to nil and the function will evaluate to false in a Boolean context.

Should a method ending in ? (question mark) return only a boolean?

I think it's just common sense and Ruby convention to do this but I have this method:
def is_subscribed?(feed_url)
Subscription.find_by_user_id_and_feed_id(self[ :id ], Feed.find_by_feed_url(feed_url))
end
The only confusion I'm getting is, this doesn't return boolean like I originally anticipated by putting the question mark on the end of the method name. I was under the impression that when evaluating an object as conditional it returns true if not nil.
Apparently I'm missing the point here and it's not evaluating it like I thought.
So, my question is, would it be best to just do an if (condition) true else false? Or is there a more elegant method of doing this?
A method ending with ? should return a value which can be meaningfully evaluated to true or false. If you want to ensure a boolean return, you can do so by adding a double bang to the finder.
def is_subscribed?(feed_url)
!!Subscription.find_by_user_id_and_feed_id(self[ :id ], Feed.find_by_feed_url(feed_url))
end
Adding a ? to the end of a method name does not in any way change the return value of the method, but instead only indicates that it is a predicate method. That is, that the method's return value should be treated as a boolean, but does not need to be strictly boolean (i.e. true or false).
Many of the other answers state that it should return a value that is truthy or falsy. This is rather redundant, since everything can be either truthy or falsy, and since all methods in Ruby return something (unless they raise an exception), the return value is always truthy or falsy.
Think of appending a ? as a nicer alternative to prepending is_ in other languages; e.g. I would either have subscribed? or is_subscribed.
It should a 'truthy' or 'falsy' value, that can be used safely in predicates, but does not have to return literal true or false. There are even methods like this, like File.size?, in the standard library.
Actually, to be specific -- methods ending in a question mark should return values that can be tested as true or false.
There are many methods in rails that return non-boolean values from '?' methods.
In fact there was recently a pull request submitted to the rails project that focussed attention on this exact matter:
https://github.com/rails/rails/pull/5582
Basically, the discussion was around this exact issue -- methods only need to return values that can be tested as true or false, like so:
if (condition)
# do 'truthy option
else
# do non-truthy option
end
From that perspective, I believe your method is fine.
The other answers cover the return value very well.
I'll add that modern style guides discourage the is_ prefix to boolean methods. The trailing question mark covers that semantic sugar.
From https://github.com/rubocop-hq/ruby-style-guide:
Boolean Methods Question Mark
The names of predicate methods (methods
that return a boolean value) should end in a question mark (i.e.
Array#empty?). Methods that don’t return a boolean, shouldn’t end in a
question mark.
Boolean Methods Prefix
Avoid prefixing predicate methods with the
auxiliary verbs such as is, does, or can. These words are redundant
and inconsistent with the style of boolean methods in the Ruby core
library, such as empty? and include?.
Another option would be to use a ternary/conditional operator to enforce a boolean return.
if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this
I do agree with others in changing your method name to
def subscribed?

How to check if a Ruby object is a Boolean

I can't seem to check if an object is a boolean easily. Is there something like this in Ruby?
true.is_a?(Boolean)
false.is_a?(Boolean)
Right now I'm doing this and would like to shorten it:
some_var = rand(1) == 1 ? true : false
(some_var.is_a?(TrueClass) || some_var.is_a?(FalseClass))
Simplest way I can think of:
# checking whether foo is a boolean
!!foo == foo
I find this to be concise and self-documenting:
[true, false].include? foo
If using Rails or ActiveSupport, you can even do a direct query using in?
foo.in? [true, false]
Checking against all possible values isn't something I'd recommend for floats, but feasible when there are only two possible values!
There is no Boolean class in Ruby, the only way to check is to do what you're doing (comparing the object against true and false or the class of the object against TrueClass and FalseClass). Can't think of why you would need this functionality though, can you explain? :)
If you really need this functionality however, you can hack it in:
module Boolean; end
class TrueClass; include Boolean; end
class FalseClass; include Boolean; end
true.is_a?(Boolean) #=> true
false.is_a?(Boolean) #=> true
As stated above there is no boolean class just TrueClass and FalseClass however you can use any object as the subject of if/unless and everything is true except instances of FalseClass and nil
Boolean tests return an instance of the FalseClass or TrueClass
(1 > 0).class #TrueClass
The following monkeypatch to Object will tell you whether something is an instance of TrueClass or FalseClass
class Object
def boolean?
self.is_a?(TrueClass) || self.is_a?(FalseClass)
end
end
Running some tests with irb gives the following results
?> "String".boolean?
=> false
>> 1.boolean?
=> false
>> Time.now.boolean?
=> false
>> nil.boolean?
=> false
>> true.boolean?
=> true
>> false.boolean?
=> true
>> (1 ==1).boolean?
=> true
>> (1 ==2).boolean?
=> true
If your code can sensibly be written as a case statement, this is pretty decent:
case mybool
when TrueClass, FalseClass
puts "It's a bool!"
else
puts "It's something else!"
end
An object that is a boolean will either have a class of TrueClass or FalseClass so the following one-liner should do the trick
mybool = true
mybool.class == TrueClass || mybool.class == FalseClass
=> true
The following would also give you true/false boolean type check result
mybool = true
[TrueClass, FalseClass].include?(mybool.class)
=> true
So try this out (x == true) ^ (x == false) note you need the parenthesis but this is more beautiful and compact.
It even passes the suggested like "cuak" but not a "cuak"... class X; def !; self end end ; x = X.new; (x == true) ^ (x == false)
Note: See that this is so basic that you can use it in other languages too, that doesn't provide a "thing is boolean".
Note 2: Also you can use this to say thing is one of??: "red", "green", "blue" if you add more XORS... or say this thing is one of??: 4, 5, 8, 35.
This gem adds a Boolean class to Ruby with useful methods.
https://github.com/RISCfuture/boolean
Use:
require 'boolean'
Then your
true.is_a?(Boolean)
false.is_a?(Boolean)
will work exactly as you expect.
No. Not like you have your code. There isn't any class named Boolean. Now with all the answers you have you should be able to create one and use it. You do know how to create classes don't you? I only came here because I was just wondering this idea myself. Many people might say "Why? You have to just know how Ruby uses Boolean". Which is why you got the answers you did. So thanks for the question. Food for thought. Why doesn't Ruby have a Boolean class?
NameError: uninitialized constant Boolean
Keep in mind that Objects do not have types. They are classes. Objects have data. So that's why when you say data types it's a bit of a misnomer.
Also try rand 2 because rand 1 seems to always give 0. rand 2 will give 1 or 0
click run a few times here.
https://repl.it/IOPx/7
Although I wouldn't know how to go about making a Boolean class myself. I've experimented with it but...
class Boolean < TrueClass
self
end
true.is_a?(Boolean) # => false
false.is_a?(Boolean) # => false
At least we have that class now but who knows how to get the right values?

What does !! mean in ruby?

Just wondering what !! is in Ruby.
Not not.
It's used to convert a value to a boolean:
!!nil #=> false
!!"abc" #=> true
!!false #=> false
It's usually not necessary to use though since the only false values to Ruby are nil and false, so it's usually best to let that convention stand.
Think of it as
!(!some_val)
One thing that is it used for legitimately is preventing a huge chunk of data from being returned. For example you probably don't want to return 3MB of image data in your has_image? method, or you may not want to return your entire user object in the logged_in? method. Using !! converts these objects to a simple true/false.
It returns true if the object on the right is not nil and not false, false if it is nil or false
def logged_in?
!!#current_user
end
! means negate boolean state, two !s is nothing special, other than a double negation.
!true == false
# => true
It is commonly used to force a method to return a boolean. It will detect any kind of truthiness, such as string, integers and what not, and turn it into a boolean.
!"wtf"
# => false
!!"wtf"
# => true
A more real use case:
def title
"I return a string."
end
def title_exists?
!!title
end
This is useful when you want to make sure that a boolean is returned. IMHO it's kind of pointless, though, seeing that both if 'some string' and if true is the exact same flow, but some people find it useful to explicitly return a boolean.
Note that this idiom exists in other programming languages as well. C didn't have an intrinsic bool type, so all booleans were typed as int instead, with canonical values of 0 or 1. Takes this example (parentheses added for clarity):
!(1234) == 0
!(0) == 1
!(!(1234)) == 1
The "not-not" syntax converts any non-zero integer to 1, the canonical boolean true value.
In general, though, I find it much better to put in a reasonable comparison than to use this uncommon idiom:
int x = 1234;
if (!!x); // wtf mate
if (x != 0); // obvious
It's useful if you need to do an exclusive or. Copying from Matt Van Horn's answer with slight modifications:
1 ^ true
TypeError: can't convert true into Integer
!!1 ^ !!true
=> false
I used it to ensure two variables were either both nil, or both not nil.
raise "Inconsistency" if !!a ^ !!b
It is "double-negative", but the practice is being discouraged. If you're using rubocop, you'll see it complain on such code with a Style/DoubleNegation violation.
The rationale states:
As this is both cryptic and usually redundant, it should be avoided
[then paraphrasing:] Change !!something to !something.nil?
Understanding how it works can be useful if you need to convert, say, an enumeration into a boolean. I have code that does exactly that, using the classy_enum gem:
class LinkStatus < ClassyEnum::Base
def !
return true
end
end
class LinkStatus::No < LinkStatus
end
class LinkStatus::Claimed < LinkStatus
def !
return false
end
end
class LinkStatus::Confirmed < LinkStatus
def !
return false
end
end
class LinkStatus::Denied < LinkStatus
end
Then in service code I have, for example:
raise Application::Error unless !!object.link_status # => raises exception for "No" and "Denied" states.
Effectively the bangbang operator has become what I might otherwise have written as a method called to_bool.
Other answers have discussed what !! does and whether it is good practice or not.
However, none of the answers give the "standard Ruby way" of casting a value into a boolean.
true & variable
TrueClass, the class of the Ruby value true, implements a method &, which is documented as follows:
Returns false if obj is nil or false, true otherwise.
Why use a dirty double-negation when the standard library has you covered?

Is There a Better Way of Checking Nil or Length == 0 of a String in Ruby?

Is there a better way than the following to check to see if a string is nil OR has a length of 0 in Ruby?
if !my_string || my_string.length == 0
return true
else
return false
end
In C# there's the handy
string.IsNullOrEmpty(myString)
Anything similar to that in Ruby?
When I'm not worried about performance, I'll often use this:
if my_string.to_s == ''
# It's nil or empty
end
There are various variations, of course...
if my_string.to_s.strip.length == 0
# It's nil, empty, or just whitespace
end
If you are willing to require ActiveSupport you can just use the #blank? method, which is defined for both NilClass and String.
I like to do this as follows (in a non Rails/ActiveSupport environment):
variable.to_s.empty?
this works because:
nil.to_s == ""
"".to_s == ""
An alternative to jcoby's proposal would be:
class NilClass
def nil_or_empty?
true
end
end
class String
def nil_or_empty?
empty?
end
end
As it was said here before Rails (ActiveSupport) have a handy blank? method and it is implemented like this:
class Object
def blank?
respond_to?(:empty?) ? empty? : !self
end
end
Pretty easy to add to any ruby-based project.
The beauty of this solution is that it works auto-magicaly not only for Strings but also for Arrays and other types.
variable.blank? will do it.
It returns true if the string is empty or if the string is nil.
nil? can be omitted in boolean contexts. Generally, you can use this to replicate the C# code:
return my_string.nil? || my_string.empty?
First of all, beware of that method:
As Jesse Ezel says:
Brad Abrams
"The method might seem convenient, but most of the time I have found that this situation arises from trying to cover up deeper bugs.
Your code should stick to a particular protocol on the use of strings, and you should understand the use of the protocol in library code and in the code you are working with.
The NullOrEmpty protocol is typically a quick fix (so the real problem is still somewhere else, and you got two protocols in use) or it is a lack of expertise in a particular protocol when implementing new code (and again, you should really know what your return values are)."
And if you patch String class... be sure NilClass has not been patch either!
class NilClass
def empty?; true; end
end
Every class has a nil? method:
if a_variable.nil?
# the variable has a nil value
end
And strings have the empty? method:
if a_string.empty?
# the string is empty
}
Remember that a string does not equal nil when it is empty, so use the empty? method to check if a string is empty.
Another option is to convert nil to an empty result on the fly:
(my_string||'').empty?
Konrad Rudolph has the right answer.
If it really bugs you, monkey patch the String class or add it to a class/module of your choice. It's really not a good practice to monkey patch core objects unless you have a really compelling reason though.
class String
def self.nilorempty?(string)
string.nil? || string.empty?
end
end
Then you can do String.nilorempty? mystring
Check for Empty Strings in Plain Ruby While Avoiding NameError Exceptions
There are some good answers here, but you don't need ActiveSupport or monkey-patching to address the common use case here. For example:
my_string.to_s.empty? if defined? my_string
This will "do the right thing" if my_string is nil or an empty string, but will not raise a NameError exception if my_string is not defined. This is generally preferable to the more contrived:
my_string.to_s.empty? rescue NameError
or its more verbose ilk, because exceptions should really be saved for things you don't expect to happen. In this case, while it might be a common error, an undefined variable isn't really an exceptional circumstance, so it should be handled accordingly.
Your mileage may vary.
If you are using rails, you can use #present?
require 'rails'
nil.present? # ==> false (Works on nil)
''.present? # ==> false (Works on strings)
' '.present? # ==> false (Works on blank strings)
[].present? # ==> false(Works on arrays)
false.present? # ==> false (Works on boolean)
So, conversely to check for nil or zero length use !present?
!(nil.present?) # ==> true
!(''.present?) # ==> true
!(' '.present?) # ==> true
!([].present?) # ==> true
!(false.present?) # ==> true
Have you tried Refinements?
module Nothingness
refine String do
alias_method :nothing?, :empty?
end
refine NilClass do
alias_method :nothing?, :nil?
end
end
using Nothingness
return my_string.nothing?
In rails you can try #blank?.
Warning: it will give you positives when string consists of spaces:
nil.blank? # ==> true
''.blank? # ==> true
' '.blank? # ==> true
'false'.blank? # ==> false
Just wanted to point it out. Maybe it suits your needs
UPD. why am i getting old questions in my feed?
Sorry for necroposting.
For code golfers:
if my_string=~/./
p 'non-empty string'
else
p 'nil or empty string'
end
Or if you're not a golfer (requires ruby 2.3 or later):
if my_string&.size&.positive?
# nonzero? also works
p 'non-empty string'
else
p 'nil or empty string'
end

Resources