Shorten Ruby code with defined? - ruby

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'.

Related

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?

Why does a return statement break the conditional operator?

Experimenting with the conditional operator in ruby,
def nada
false ? true : nil
end
def err
false ? true : raise('false')
end
work as expected but
def reflection
false ? true : return false
end
produces a syntax error, unexpected keyword_false, expecting keyword_end
def reflection
false ? true : return(false)
end
and attempted with brackets syntax error, unexpected tLPAREN, expecting keyword_end
yet
def reflection
false ? true : (return false)
end
works as expected, and the more verbose if...then...else...end
def falsy
if false then true else return false end
end
also works as expected.
So what's up with the conditional (ternary) operator?
You can use it like this, by putting the entire return expression in parentheses:
def reflection
false ? true : (return false)
end
Of course, it does not make much sense used like this, but since you're experimenting (good!), the above works! The error is because of the way the Ruby grammar works I suppose - it expects a certain structure to form a valid expression.
UPDATE
Quoting some information from a draft specification:
An expression is a program construct which make up a statement (see 12
). A single expression can be a statement as an expression-statement
(see 12.2).12
NOTE A difference between an expression and a statement is that an
expression is ordinarily used where its value is required, but a
statement is ordinarily used where its value is not necessarily
required. However, there are some exceptions. For example, a
jump-expression (see 11.5.2.4) does not have a value, and the value
of the last statement of a compound-statement can be used.
NB. In the above, jump-expression includes return among others.
I think this is all related to the ruby parser.
ruby parses return as the else-expression of the ternary operator
ruby is then surprised when it finds false instead of end
wrapping return false in parentheses causes ruby to interpret the entire thing as the else-expression
return(false) doesn't work because ruby is still trying to interpret just the return part as the else-expression, and is surprised when it finds a left-parenthesis (updated)
Note: I don't think this is a great answer.
A great answer could, for example, explain the parse errors with reference to the ruby grammar.
The ternery operator is just that, an operator. You don't return from it. You return from functions. When you put a return in an if, you return from the function that the if is in. Since there is no variable awaiting assignment from the result of the if, there is no problem. When you return from the ternery operator, there is no value assigned to the variable.

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.

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

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.

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