I'm currently reading The Ruby Programming Language, and I am not sure how to read Ruby-esque if else statements properly. Can you help me write the ruby code below in the second code block in regular if-else statements like this?
if some_condition
return x
else
return y
end
So the ruby codes I am unsure of are these.
minimum = if x < y then x else y end
max = x > y ? x : y
Thank you!
Both of the forms you seem to be having difficulty with make use of an idea Ruby takes from the Functional Programming paradigm: namely, Everything is an expression, and therefore returns a value. This is even true for conditional statements, an idea that languages like Java don't really support (for example:
public boolean test() {
boolean x = if (1 > 2 ) { false; } else { true; };
return x;
}
simply isn't syntactically valid).
You can see this in a Ruby terminal:
will_be_assigned_nil = false if (1 > 2) # => nil
will_be_assigned_nil # => nil
So, to your question.
The first one can be rewritten like this:
if x < y
mininum = x
else
minimum = y
end
The second is like the ternary operator in other languages, and is equivalent to:
if x > y
max = x
else
max = y
end
It's helpful to remember the roots & heritage of languages when trying to understand their constructs. Ruby shares the "More Than One Way To Do It" philosophy with Perl, and idiomatic Ruby code often has a high emphasis on elegance.
The "post-expression"-style conditionals are a good example of this. If I have guard expressions at the start of my methods, it's not uncommon for me to write:
raise "Pre-condition x not met" unless x # (or "if !x" , preference thing)
raise "Pre-condition y not met" unless y # etc., etc.
instead of
if !x
raise "Pre-condition x not met"
end
if !y
raise "Pre-condition y not met"
end
Related
I did:
x = :foo, y = %q{foo}.to_sym, x.==(y)
# => [:foo, :foo, false]
I am wondering why :foo is not equal to :foo.
Parallel assignment works differently in Ruby, and if you want multiple statements on one line, you need to separate them with semicolons (not commas).
The statement you executed:
x = :foo, y = %q{foo}.to_sym, x == y
Is equivalent to:
x = [:foo, y = %q{foo}.to_sym, x == y]
N.B. x is not yet defined when the right-hand side of the expression is evaluated, so the last term is effectively comparing nil and :foo. The y assignment also happens while the right-hand side of the expression is evaluating, and the result gets included in the array literal being assigned to x.
Here's what you meant to do:
x, y = :foo, %q{foo}.to_sym; x == y # => true
Just an aside, x.==(y) works because :== is technically a method, but in idiomatic Ruby you just write x == y. The interpreter knows what you mean.
Nice answer, but there is a logical leap from "x is not yet defined" to "the last term is effectively comparing nil and :foo.", in particular, why an undefined variable is evaluated as nil is unexplained.
This has to do with how variable hoisting is implemented in Ruby. It's an obnoxious feature of JavaScript too.
I often find myself doing things like this:
do_something if x && x == y
In other works, do something if x is not nil, and it has a value of y.
It would be nice if I could do something like this instead:
do_something if x &&== y
Is there an operator that does this?
Responses to comments:
x == y - The problem with this, is that it only tests existence (not nil) if the value of y is known. If y is itself nil then the check fails. So you could end up doing:
y && x == y
x ||= y - This would assign the value of y to x if x is nil. That's not what I'm looking for. x &&= y doesn't work either for the same reason - it changes the value of x to y if x exists.
An example: in my current scenario I want to check that a user has passed to a controller the token associated with them, but I also want to ensure that the token has been assigned. Something like:
do_something if user.token && user.token == params[:token]
If you are using ruby > 2.3.0 you can use the &. operator: x&.== y. It basically does what .try does in Rails if the value of the operand is different than nil it calls the method and returns its result. If the value is nil it returns nil so you can do things like: do_i_exist&.does_the_result_exist&.nil?
See: What does &. (ampersand dot) mean in Ruby?
What is the difference between if !variable == 10 {...} and if variable != 10 {...} in Ruby programming language? Of course this can be applied to all other languages. In first case are we just negating condition, and in second testing if variable is actually unequal to 10?
if variable != 10 is equivalent to unless variable == 10
while !variable is negating the variable, so first it's evaluated as an expression, then negated.
Example
variable = 5
variable != 10 # => true
!variable # => false (5 is evaluated to true, then negated)
!variable = 10 # => warning: found = in conditional, should be ==
To a large degree all programming languages, including Ruby, follow boolean algebra rules that state there's a number of ways to express the same condition.
x != y
!(x == y)
!!(x != y)
This also plays out in other domains, such as:
!x && !y
!(x || y)
As others have pointed out, be very careful when using the == comparator instead of the = assignment operator.
I want to emphasize I am looking for the actual way the ||= operator is expanded by the Ruby 1.9.3 interpreter, not how it appears to be expanded based on its behavior. What I'm really hoping for is someone who has grokked the actual interpreter source, a task which I sadly am probably not up to. The only resource I have found that appears to examine this question is out of date: "A short-circuit (||=) edge case".
The resource I mentioned above seems to suggest that the "official" expansion of x ||= y to x = x || y was either inaccurate or buggy in interpreter versions prior to 1.9. In any case, the edge case indicated seems to have been smoothed out. The resource above claims that x || x = y or x or x = y are "more accurate". Neither of those, however, is correct, because they don't work when x is a previously undeclared global variable:
[11:04:18][****#asha:~]$ irb
1.9.3-p194 :001 > a || a = 3
NameError: undefined local variable or method `a' for main:Object
1.9.3-p194 :002 > b or b = 3
NameError: undefined local variable or method `b' for main:Object
1.9.3-p194 :003 > c = c || 3
=> 3
So in 1.9.3, at least, the x = x || y expansion appears to be correct, as far as these examples are concerned. However, to reiterate my original point, I would really like to see some truly authoritative source resolve this question, well, authoritatively rather than anecdotally as I (and others) have done.
x ||= y
is a shorthand form for
x || x = y
If x is not nil and x is not false, the assignation will have place because of the short-circuit evaluation of the || operator.
EDIT: This post is about the spec, read the comments to get the somewhat less ideal "implementation story"
The Ruby draft spec (PDF) section 11.4.2.3.2 defines it fairly specifically (even if fairly hard to interpret); let's do a (theoretically somewhat loose) example with c ||= 3;
a) Evaluate the variable as a variable reference (see 11.5.4). Let V be the resulting value.
V is set to the value of c
b) Evaluate the operator-expression or the method-invocation-without-parentheses. Let W be the resulting value.
W is set to 3.
c) Let OP be the assignment-operator-name of the assignment-operator.
OP is set to ||
d) Let X be the operator-expression of the form V OP W.
X is set to c || 3.
e) Let I be the variable of the abbreviated-variable-assignment-expression or the abbreviated- variable-assignment-statement.
I is set to refer to c.
f) Evaluate a single-variable-assignment-expression (see 11.4.2.2.2) where its variable is I and the operator-expression is X.
c = c || 3 is evaluated.
g) The value of the abbreviated-variable-assignment is the resulting value of the evaluation.
The result of the assignment is 3.
In other words, the expansion c = c || 3 is (excluding bugs like in pre-1.9) correct.
I'm looking for a semantic or language construct that will simplify some of my if statements. If I have an if statement with an or, where I 'choose' between two values, I'd like to have that chosen variable available later on in the code.
I'll write this in pseudo-code:
if ( x or y ) {
function(z);
}
Where z is the value of x or y, whichever triggered the if to be true. Otherwise I'm writing
if ( x ) {
...
function(x);
}
if ( y ) {
...
function(y);
}
Now in that example the duplication isn't much, but in my actual situation, there are about 6 lines of code that would be identical duplication within each if block. So I write something like:
if ( x ) {
z = x;
}
if ( y ) {
z = y;
}
if ( z ) {
...
function(z);
}
But that just seems so roundabout I suspect that somewhere along the line some guru came up with a nice syntax to make a one-line if. Is there a construct in a language anywhere where I can bind the triggering value into a variable in the subsequent block? What would this structure be called?
The actual situation I'm working in is in PHP, so I realize PHP may not have this capability.
In Python (also Ruby), the expression x or y evaluates to x if it is true, otherwise y. You could write the statement as f(x or y), or z = x or y.
For this exact situation. You can use the ? operator:
z = x ? x : y;
Which reads: z is (if x is not false) x otherwise it is y.
Actually, something like
if ( $z = ( $x ? $x : $y ) ) {
function($z);
}
Works as advertised in PHP. Thanks, slebetman!