Ruby - Question Mark usage in Class Method - ruby

I'm having a little difficulty in understanding the below under initialize, and color methods. This is from the solution I was given:
The one under initialize:
I think it means #given equals value, and if value is equal to 0, then its false, otherwise its true
Under color not sure what the 2nd question mark means.
def initialize(value)
#value = value
#given = value == 0 ? false : true
end
def color
given? ? :blue : :red
end
def given?
#given
end

Under color not sure what the 2nd question mark means.
This is called the conditional operator. (See, for example, section 11.5.2.2.5 Conditional operator expression of the ISO Ruby Language Specification.)
condition ? consequence_truthy : consequence_falsy
will evaluate condition and depending on whether the result is truthy or falsy, it will evaluate either the first or the second consequence.
Personally, I find the conditional operator useless in Ruby. In C and similar languages, the conditional operator is required because it is an expression, whereas the conditional statement is, well, a statement. So, if you need to use a conditional in an expression, you cannot use a conditional statement, you must use the conditional operator.
However, this does not apply to Ruby: in Ruby, everything is already an expression, there are no statements. The conditional expressions (see, for example, section 11.5.2.2.2 The if expression, section 11.5.2.2.3 The unless expression, and section 11.5.2.2.4 The case expression) can already be used as an expression, so there is no need to use the conditional operator.
Personally, I find the conditional expression more readable than the conditional operator:
if condition then consequence_truthy else consequence_falsy end
This is semantically equivalent to the conditional operator, the only difference is syntactical: it has different precedence, which however, actually works more natural than the precedence of the conditional operator.
So, your examples could, in my opinion, be clearer written as
def initialize(value)
#value = value
#given = if value == 0 then false else true end
end
def color
if given? then :blue else :red end
end
Actually, the initialize contains a useless-use-of-conditional because Integer#== already returns a boolean. So, the following would be even clearer:
def initialize(value)
#value = value
#given = value != 0
end

Mostly we use ? mark as a part of the method's name which returns boolean value. this is just a convention we ruby coders use to follow.
In your example given? is the method name as it return boolean value so here we have follow the convention.
and in ternary conditional operator we use
condition ? do something when condition is true : do something when condition is false
In your case
given? it's returning true or false and which is also method name
So the first question mark is a part of the method name and 2nd question mark is the part of ternary condition

Related

Last expression evaluated in Ruby

I have this class definition:
class Test
attr_accessor :state
def multiple_state=(times)
#state *= times
end
end
obj = Test.new
obj.state = 2
puts #{obj.multiple_state=4}
I thought the output is 8, coz that is the value of the last
expression evaluated in multiple_state. (?)
But the output is 4.
Is my understanding of last expression evaluated wrong?
Thanks.
Ruby's syntactic sugar for setter methods always returns the right side of the assignment, even if you do something else in your method. The Well-Grounded Rubyist puts it better than I could:
Setter methods don’t return what you might think. When you use
the syntactic sugar that lets you make calls to = methods that look like assignments,
Ruby takes the assignment semantics seriously. Assignments (like x = 1)
evaluate to whatever’s on their right-hand side. Methods usually return the
value of the last expression evaluated during execution. But = method calls
behave like assignments: the value of the expression ticket.price = 63.00 is
63.00, even if the ticket= method returns the string "Ha ha!". The idea is to
keep the semantics consistent. Under the hood, it’s a method call; but it looks
like an assignment and behaves like an assignment with respect to its value as
an expression.
The Well-Grounded Rubyist - Chapter 3.3.3

doubts regarding "||=" OR EQUALS operator in ruby [duplicate]

This question already has answers here:
What does ||= (or-equals) mean in Ruby?
(23 answers)
Closed 8 years ago.
I have some doubts regarding OR EQUALS (||=) operator in ruby. How does ruby interpreter implement it? Here is a sample of code:
class C
def arr
#num ||= []
end
end
When we use OR EQUALS operator in this circumstances, the first call to this method initializes the variable and adds an element, that's fine. When a second call is made to arr, how does it know that array has one element in it..
In Ruby, there are two values that are considered logical false. The first is the boolean value false, the other is nil. Anything which is non-nil and not explicitly false is true. The first time though the method, #num is nil, which is treated as false and the logical or portion of ||= needs to be evaluated and ends up assigning the empty array to #num. Since that's now non-nil, it equates to true. Since true || x is true no matter what x is, in future invocations Ruby short circuits the evaluation and doesn't do the assignment.
In general terms x ||= y is equivalent to x = x || y, it's just shorthand. It's implemented as the expanded form, same as &&=, += or -=.
Most programming languages, Ruby included, will stop executing a logical comparison statement like || on the first true value it encounters and return that. Likewise, it will halt on the first false value when using &&.
In general terms:
false || foo()
This will return false and not evaluate foo().
The pattern is best described as a "lazy initializer", that is the variable is defined only once, but only when it's actually used. This is in contrast to an "eager initializer" that will do it as early as possible, like inside the initialize method.
You'll see other versions of this pattern, like:
def arr
#num ||= begin
stuff = [ ]
# ...
stuff
end
end
This handles cases where the initial value is not as trivial and may need some work to produce. Once again, it's only actually generated when the method is called for the first time.
How does Ruby know on the second pass to not initialize it again? Simple, by that point #num is already defined as something.
As a note, if you're using values like false that would evaluate as non-true, then ||= will trigger every time. The only two logically false values in Ruby are nil and false, so most of the time this isn't an issue.
You'll have to do this the long-form way if you need to handle false as well:
def arr
return #num unless num.nil?
#num = false
end
There was talk of adding an ||=-like operator that would only trigger on nil but I don't think that has been added to Ruby yet.

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, define []= operator, why can't control return value?

Trying to do something weird that might turn into something more useful, I tried to define my own []= operator on a custom class, which you can do, and have it return something different than the value argument, which apparently you can't do. []= operator's return value is always value; even when you override this operator, you don't get to control the return value.
class Weird
def []=(key, value)
puts "#{key}:#{value}"
return 42
end
end
x = Weird.new
x[:a] = "a"
output "a:a"
return value => "a" # why not 42?
Does anyone have an explanation for this? Any way around it?
ruby MRI 1.8.7. Is this the same in all rubys; Is it part of the language?
Note that this behavior also applies to all assignment expressions (i.e. also attribute assignment methods: def a=(value); 42; end).
My guess is that it is designed this way to make it easy to accurately understand assignment expressions used as parts of other expressions.
For example, it is reasonable to expect x = y.a = z[4] = 2 to:
call z.[]=(4,2), then
call y.a=(2), then
assign 2 to the local variable x, then finally
yield the value 2 to any “surrounding” (or lower precedence) expression.
This follows the principle of least surprise; it would be rather surprising if, instead, it ended up being equivalent to x = y.a=(z.[]=(4,2)) (with the final value being influenced by both method calls).
While not exactly authoritative, here is what Programming Ruby has to say:
Programming Ruby (1.8), in the Expressions section:
An assignment statement sets the variable or attribute on its left side (the lvalue) to refer to the value on the right (the rvalue). It then returns that value as the result of the assignment expression.
Programming Ruby 1.9 (3rd ed) in section 22.6 Expressions, Conditionals, and Loops:
(right after describing []= method calls)
The value of an assignment expression is its rvalue. This is true even if the assignment is to an attribute method that returns something different.
It’s an assignment statement, and those always evaluate to the assigned value. Making this different would be weird.
I suppose you could use x.[]= :a, "a" to capture the return value.

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.

Resources