Ruby, !! operator (a/k/a the double-bang) [duplicate] - ruby

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
What does !! mean in ruby?
Hi,
I'm new to Ruby and can't find anywhere description of what "!!" means.
Here's an example:
def signed_in?
!!current_user
end
If this is a double negative, why not to say:
def signed_in?
current_user
end
Please help.

In Ruby (and many other languages) there are many values that evaluate to true in a boolean context, and a handful that will evaluate to false. In Ruby, the only two things that evaluate to false are false (itself) and nil.
If you negate something, that forces a boolean context. Of course, it also negates it. If you double-negate it, it forces the boolean context, but returns the proper boolean value.
For example:
"hello" #-> this is a string; it is not in a boolean context
!"hello" #-> this is a string that is forced into a boolean
# context (true), and then negated (false)
!!"hello" #-> this is a string that is forced into a boolean
# context (true), and then negated (false), and then
# negated again (true)
!!nil #-> this is a false-y value that is forced into a boolean
# context (false), and then negated (true), and then
# negated again (false)
In your example, the signed_in? method should return a boolean value (as indicated by convention by the ? character). The internal logic it uses to decide this value is by checking to see if the current_user variable is set. If it is set, it will evaluate to true in a boolean context. If not, it will evaluate as false. The double negation forces the return value to be a boolean.

In most programming languages, including Ruby, ! will return the opposite of the boolean value of the operand. So when you chain two exclamation marks together, it converts the value to a boolean.

!! is just ! (the boolean negation operator) written twice. It will negate the argument, then negate the negation. It's useful because you can use it to get a boolean from any value. The first ! will convert the argument to a boolean, e.g. true if it's nil or false, and false otherwise. The second will negate that again so that you get the boolean value of the argument, false for nil or false, true for just about everything else.
In Ruby you can use any value in an if statement, e.g. if current_user will execute if the current user is not nil. Most of the time this is great because it saves us typing explicit tests (like if !current_user.nil?, which is at least six characters longer). But sometimes it might be really confusing if you return an object when the method implies that it returns a boolean. Methods whose name ends with ? should return truthy or falsy values, i.e. they return something that will evaluate to true or false. However, it can get really messy if signed_in? returned a user object. For example if you're trying to debug why some code that uses signed_in? doesn't work you will probably get really confused when a user object turns up where you expected true or false. In that situation it's useful to add !! before the return since that guaranteed that the truthy or falsy value will be returned as either true or false.

As you rightly understood it is a double-negative use of the ! operator. That said, while it can be a shorthand way to check for whether a variable can be nil or not, IMO that's too concise. Take a look at this and this post. Note that in Ruby, testing something to nil will evaluate to false.

Related

Return boolean value based on string boolean input values

I have a paramter params[:input], and its value is coming as 'true' or 'false' (boolean values in string).
In database, the input values are stored as 1 and 0. I need to return boolean values based on input string values. I created a function below to return boolean values.
def status(input)
return unless input.present?
return false if ['false'].include?(input.downcase)
return true if ['true'].include?(input.downcase)
end
Not sure if this is the best way. Is there a better way to write this?
I would go with case. Since there is a binary state, you probably need to decide what value is to be chosen for a fallback. E. g. when no parameter is present, you are likely still in a need to return something. I would return false for everything save for 'true':
def status(input)
case input
when 'true' then true
when 'false' then false
else false
end
end
Or, even shorter (but less readable/idiomatic):
def status(input)
'true' == input
end
It seems like you want to cast a string to a boolean and you are using Ruby on Rails. Why don't you use the same method that Rails itself uses to translate user input into a boolean?
def status(input)
ActiveRecord::Type::Boolean.new.type_cast_from_user(value)
end
The name of the method changed in different versions of Rails. The above version is for Rails 4.2. Prior Rails 4.2 use ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value) and since Rails 5 it is ActiveRecord::Type::Boolean.new.cast(value)
The advantage of using the build method it that it accepts not only the strings 'true' and 'false' but other common input and still returns a useful boolean.
The simplest solution, without overhead of switch statements, etc, is simply this:
def status(input)
input.is_a?(String) && input.casecmp?('true')
end
casecmp? ensures case-insensitivity, so 'true', 'TRUE', 'True', and any variation of different cases would all return a boolean true.
This could even be altered slightly more to simply ensure that input is a string by calling to_s on it, which will just return self if it is already a string.
def status(input)
input.to_s.casecmp?('true')
end
The first is a bit safer, as depending on the object passed, to_s could have been overridden and supply unpredictable behavior, though highly unlikely.
Another solution is using downcase and comparing with ==, but casecmp? is more optimized for comparison, and does not create an additional string as downcase would.
Documentation for case_cmp?

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?

Shorten Ruby code with defined?

Is there a shorter way of writing next code in Ruby:
if defined?($servlet_context) then true
else false
end
The defined? operator evaluates to a string or nil:
The defined? operator returns nil if its argument (which can be an arbitrary expression) is not defined, otherwise it returns a description of that argument.
So if you just want something truthy then defined?($servlet_context) will do. However, if you absolutely must have a boolean value, then you can use a double-bang cast:
!!defined?($servlet_context)
defined?($servlet_context) will have the exact same effect.
Also then is not required in ruby so the easiest way to shorten it is - remove 'then'.

Ruby boolean double negation convention

Can anybody tell me why a lot of Ruby boolean methods use this double negation convention?
!!(boolean expression)
The double negation ensures that no matter the initial value, you will always get true or false, never some mystery value.
This is handy because it avoids dangling references to objects you no longer require, or having to differentiate between two types of false value, nil and false.
Often you will see methods written like this:
def logged_in?
!!#session_user
end
This will return true or false and that value can be used for whatever purpose is required. Compare that with this:
def logged_in?
#session_user
end
In this case if you save the value, you're actually saving the whole #session_user object, which could be a fairly significant chunk of memory. This memory cannot be released until your reference to it falls out of scope. Since there is only one true and one false, there's no need for garbage collection.
Suppose you want to define a method that returns a boolean. For example, whether a string matches a regex.
class String
def include? regex; self =~ regex end
end
If you do the above, it will return nil when it does not match, and an integer when it matches. In many cases, that does not matter so much (nil is similar to false and true can be substituted for an integer). But if you really wanted a boolean as a return value, if you do
class String
def include? regex; !!(self =~ regex) end
end
it will return true when it matches, false when it does not.
In my opinion, Ruby is just a little too clever about Booleans. This is a workaround for the cases when the cleverness causes problems.
Here's the excessive cleverness: there's no Boolean class. Instead, there's a convention under which any value can serve as a boolean. In a context where a true-or-false value is required, nil or false means "false" and anything else means "true". The values true and false are not part of a special class, they're the sole members of their respective classes — they exist only to make code a little more readable.
I guess this works fine most of the time, but every once in a very long while you need a boolean value that is always true or false. For example, I recently needed to compare two boolean values and do something special if they were different; the only problem being, one of them was either true or false, while the other was either 1 or nil. Fix? Utilize the fact that !!nil == false and !!1 == true.

Double ampersand in Ruby

I am using the authlogic gem with Ruby on Rails, and I have been using the following to obtain the id of the user that is currently logged in:
current_user = UserSession.find
id = current_user && current_user.record.id
I'm not understanding how current_user && current_user.record.id returns the current user id. I would think this would return a boolean. Can someone explain how this works?
There is no Boolean type in Ruby; Ruby has a rather simple view of truth (or more precisely, it has a rather simple view of falsehood).
the false object, which is the singleton instance of FalseClass is considered falsy
the nil object, which is the singleton instance of NilClass is falsy
every other object is truthy (including, obviously, the true object, which is the singleton instance of TrueClass)
[BTW: this means that a lot of objects that are considered falsy in some other languages, are actually truthy in Ruby, like the integer 0, the real value 0.0, the empty string, the empty array, the empty hash, the character 'F']
So, the Boolean operators &&, ||, and and or do not return Boolean values. Instead they return the first object that determines the outcome of the expression.
(They are also short-circuiting, which means that they only evaluate the minimum sub-expressions that are needed to determine the outcome of the expression. So, an alternate formulation would be that they return the result of the last expression that was evaluated. Which, in turn, is analogous to what blocks, methods, class bodies and module bodies do.)
So, what does it mean to return the first object that determines the outcome? That's simple, really: the result of the expression
a && b
is truthy if both a and b are truthy, otherwise it is falsy. So, if a is falsy, it is completely irrelevant what b is: the result will be falsy either way. So, we might just as well simply return a. (Remember, a doesn't have to be false, it could also be nil and the programmer might want to know which one of the two it was.)
If, OTOH, a is truthy (IOW it is neither nil nor false), then the result of the whole expression is solely dependent on b: if b is truthy, the whole result will be truthy, otherwise if b is falsy, the whole result will be falsy. So, we might just as well return b itself, instead of first converting it to a Boolean.
|| and or are analogous or more precisely dual to && and and.
You posted this example:
id = current_user && current_user.record.id
Here, the author isn't even expecting current_user to be a Boolean value! Instead, he expects it to be either a User or nil. But that's perfectly fine, because a User is truthy and nil is falsy, so they still can be used in a Boolean expression.
The basic intention is that the author wants to prevent a NoMethodError exception being raised, if he tries to call #record on nil.
An alternative way of expressing this would be
id = current_user.record.id unless current_user.nil?
If you want all the gory details, check out Section 11.1 (page 36) of the Draft ISO Ruby Specification or the excutable specifications of the RubySpec project. (Here's the one for &&.)
I wrote a pure Ruby implementation of Ruby's Boolean operators and conditional expressions once for fun. The meat of the implementations is these two mixins.
The logical and is short circuiting. That means that if the construct is X && Y, and X is false then Y never gets checked because the whole thing is certainly going to be yield false.
That code is saying, essentially:
if (current_user is TRUE) {
id = current_user.record.id;
]
Here's some console output showing you get the second value if the first is true:
irb(main):005:0> true && 9
=> 9
and nil if the first is nil:
irb(main):008:0> nil && 9
=> nil

Resources