Compound Boolean Expr: Void Value Expression - ruby

def success?
return #fhosts.empty? and #khosts.empty? and #shosts.any?
end
When I run that instance method, I get an error:
/home/fandingo/code/management/lib/ht.rb:37: void value expression
return #fhosts.empty? and #khosts.empty? and #shosts.any?
I'm confused by what's happening since this works
def success?
#fhosts.empty? and #khosts.empty? and #shosts.any?
# This also works
# r = #fhosts.empty? and #khosts.empty? and #shosts.any?
# return r
end
I'm coming from a Python background, and I don't want anything to do with implicit returns. Programming has plenty of landmines as it is.
If we have an arbitrary expression, E, that consists of boolean operations and and or together, here are some operations we could perform:
if E -- works
E -- works
* v = E -- works
return E -- broken
Why doesn't the last case work?
Edit: Actually v = E doesn't work. Only
v = Ei
is evaluated. Ei+1...k are ignored.

This is likely due to the very weak binding of and which causes it to parse out differently than you expect:
return x and y
This actually means:
(return x) and y
Since you're returning immediately it doesn't have a chance to evaluate the remainder of the expression.
Your version without return is correct:
x and y
This doesn't have a binding issue and is more idiomatic Ruby. Remember you only need to put an explicit return if you're trying to force an exit before the last line of the method. Being opposed to implicit returns is going to make your code look heavily non-Ruby. They're one of the reasons Ruby is so clean and simple, and how things like a.map { |v| v * 2 } works.
The When in Rome principle applies here. If you want to write Python-style Ruby you're going to be going against the grain. It's like saying "I don't like how you say X in your spoken language, so I'll just ignore that and do it my way."
This should also work:
return x && y
The && method is very strongly bound so return is the last thing evaluated here.
Or if you really want to use and for whatever reason:
return (x and y)

Related

Why is x-- a valid ruby statement but it doesn't do anything?

I know ruby doesn't support integer increment x++ or decrement x-- as C does. But when I use it, it doesn't do anything and doesn't throw an error either. Why?
Edit:
Sorry the code I actually found was using --x, which is slightly different, but the question remains: Why?
x = 10
while --x > 0
y = x
end
In Ruby, operators are methods. --x, x++, x==, etc all can do wildly different things. -- and ++ are not themselves valid operators. They are combinations of operators.
In the case of your provided code, --x is the same as -(-x).
If x = 5, then -x == -5 and --x == 5.
---x would be -(-(-x)), and so on.
Similarly, x-- alone on a line is technically valid, depending on what the next line of code contains.
For example, the following method is valid:
def foo
x = 1
y = 10
x--
y
end
The last two lines of that method get interpreted as x - (-y) which calculates to 1 - (-10).
The result doesn't get assigned to any value, so the x-- line would appear to do nothing and the function would just return the result: 11.
You could even have nil on the last line of the function instead of y, and you wouldn't get a syntax error, but you would get a runtime error when the function is called. The error you would receive from x--nil is:
NoMethodError: undefined method `-#' for nil:NilClass
That means that -nil is invalid since nil does not define the method -#. The # indicates that - works as a unary operator. Another way to express --x by invoking the unary operators manually is x.-#.-#
x-- just on its own is not valid. It requires a Numeric object to follow it (or any object which implemented -#). That object can be on the next line. x== would work the same way.
But when I use it, it doesn't do anything and doesn't throw an error either.
It does:
ruby -ce 'x--'
# -e:1: syntax error, unexpected end-of-input
x-- is not valid Ruby syntax.

'==' type and pattern matching - wait for the other recursive calls and do nothing on a case

I have two questions concerning OCaml.
Firstly, what does the == means when defining a type.
For example you can see at the end of this page the following code:
type compteur == int;;
Then what is the difference with:
type compteur = int;;
Moreover I have an other question concerning pattern matching.
How to say that you want to return nothing on a case.
For example let's say I have a function f that returns a boolean:
let rec f v = function
| t when t<v -> true
| t when t > v -> f (t-1)
| t when t = v -> (* here a code to say that you do nothing, and wait for the other recursive call *)
type compteur == int is a syntax error. The only valid way to define a type alias is with =, not ==. It's just a typo on the page you linked.
How to say that you want to return nothing on a case.
The only way to return nothing from a function would be to exit the program, raise an exception or loop (or recur) infinitely. Otherwise a function always returns a value.
here a code to say that you do nothing, and wait for the other recursive call
What other recursive call? In the case that t = v only the code for that case will run. There is no other code to wait on.

Do "Ors" Evaluate The Whole Expression?

Say I have the following statement logic (I'll be using VBA for this example, but it also pertains to other languages)
x = 1
y = 2
z = 1000
If x = 1 Or y = 2 Or z = 4 Then
Execute Code
End
Does the compiler or executing program find that the first value is true, and then continue to Execute Code or does it finish off the rest of the statement?
I can't speak for VBA, but I can say that it is language specific. In some languages, the programmer has the ability to use "short-circuit" AND and OR expressions. Short-circuiting is the process of no longer evaluating a boolean expression if the result has already been determined.
If using a short-circuited AND, the boolean operation stops early if a FALSE is found. If using a short-circuited OR, the boolean operation stops early if a TRUE is found.
For example, in Java:
a || b is a short-circuited OR
a | b is a non-short-circuited OR
a && b is a short-circuited AND
a & b is a non-short-circuited AND
Some may ask, "why would I ever use a non-short-circuited AND or OR?" The reason for this comes when you are calling a function that returns a boolean that you want to run in every case. For example a() | b() would run both function a and function b. a() || b() only runs function b if a returns false.
I think that also in vba you can use OrElse.
'Or' (bitwise comparison) always finishes the rest of the statement, 'OrElse' (logical comparison) stops when the requirement is met.
In C++, C# and Java you can use '|' and '||'.
For example if object is null Or object.value = "" will result in a null exception when the object is empty because of the attempt to access a field from an empty object.
With OrElse the evaluation if object is null OrElse object.value = "" will stop at the first comparison when an empty object is evaluated.

Why isn't `method=` treated the same as any other method?

Consider the following code snippet:
class Example
def my_attr=(value)
#_my_attr = value
#_my_attr * 3
end
end
I expect the expression Example.new.my_attr = 5 to return 15, but that turns out to be wrong. The original return value is always returned, even when I call the = method explicitly:
Example.new.my_attr = 5 # => 5
Example.new.my_attr=(5) # => 5
How and why does Ruby do this? Does Ruby treat methods that end in = specially, or is it some other mechanism? I guess this precludes chaining on return values of = methods, right? Is there a way to make Ruby behave differently, or is this just how it is?
Update: Credit to #jeffgran for this:
Example.new.send(:my_attr=, 5) # => 15
This is a workaround, but on another level even more perplexing, since that would mean send is clearly not always equivalent in behavior to calling a method directly.
This is how assignment works; the return value is ignored, and the result of an assignment expression is always the right-hand value. This is a fundamental feature of Ruby's grammar. left-hand side = right-hand side will always evaluate to right-hand side, regardless of whether left hand side is a variable (x), a method (object.x), a constant (X) or any expression.
Source: Programming Languages | Ruby
IPA Ruby Standardization WG Draft, 11.4.2.2.5, Single method assignments
Consider chaining of assignments, x = y = 3.
For this to work correctly, the result of y = 3 must be 3, regardless of the actual value returned by the y= method. x = y = 3 is meant to read as y = 3; x = 3, not as y = 3; x = y which is what would be implied if the return value from y= was treated as the result of y = 3.
Or consider all the other places assignment can be used. Sometimes, instead of this...
obj.x = getExpensiveThing()
if obj.x
...
... we write this ...
if obj.x = getExpensiveThing()
This couldn't work if the result of obj.x = ... could be any arbitrary thing, but we know it will work because the result of obj.x = y is always y.
Update
A comment on the question states:
Interesting, I wasn't aware of this scenario. It seems that method= returns whatever input is given...
No, it's an important distinction to make. This has nothing to do with the return value of method assignment, and it definitely does not "return whatever input is given", it returns whatever you tell it to return.
The whole point is that the return value is ignored by the grammar of the language; assignment doesn't evaluate to the return value of the attr= method, but the return value still exists as evidenced by the question itself: Example.new.send(:my_attr=, 5) # => 15. This works because it is not assignment. You're side-stepping that part of the Ruby language.
Update again
To be clear: x and y in my examples shouldn't be interpreted as literal Ruby variables, they are place holders for any valid left-hand side of an assignment. x or y could be any expression: a, obj.a, CONSTANT_A, Something::a, #instance_a, it's all the same. The value of assignment is always the right-hand side.

Ruby: Assign output of a function only if it does not return nil

When programming in Ruby I quite often have assignments like the following
test = some_function if some_function
With that assignments I want to assign the output of a function, but if it returns nil I want to keep the content of the variable. I know there are conditional assignments, but neither ||= nor &&= can be used here. The shortest way I found to describe the statement above is
test = (some_function or test)
Is there a better / shorter way to do this?
I don't think there's anything better than the last snippet you showed but note that or is used for flow control, use || instead:
test = some_function || test
It's usually better to assign new values to new names, the resulting code is easier to understand and debug since variables/symbols have the same value throughout the scope:
some_different_and_descriptive_name_here = some_function || test
I'd just add parentheses
(a = b) unless b.nil?
(a = b) if b
being inferior because if b is false then a remains as before
Keep in mind that this evaluates b twice, so if b is a function with side-effects (such as changing variables outside of its scope or printing) it will do that twice; to avoid this you must use
temp = b; (a = temp) unless temp.nil?
(which can, of course, be split into)
temp = b
(a = temp) unless temp.nil?

Resources