I was wondering if somebody could please explain to me what the dash place holder does?
def remove_every_other(arr)
arr.select.with_index { |_,idx| idx.even? }
end
In some sense, this is just another parameter like any other. There is no difference between the parameter named _ and the parameter named idx. They are both parameters like any other parameter.
So, in some sense, there is nothing special about _: it's a name like any other name and could just as well be named foo or bar or baz.
However, that is not quite true: _ is treated special by the Ruby language. More precisely, any local variable name or parameter name starting with _ is treated special by the Ruby language.
In many communities, the identifier _ or identifiers starting with _ are used to signify that something is being deliberately ignored. And this is also the usage in the Ruby community.
In order to support this usage of _ for ignored variables or parameters, the Ruby language treats local variables and parameters starting with _ special in two ways:
Unused local variable warnings
Ruby will generate warnings for unused local variables:
a = 42
b = 42
b
will generate "warning: assigned but unused variable - a".
However, if I rename the variable to _a or _, the warning will be suppressed:
_a = 42
_ = 42
b = 42
b
Duplicate parameter SyntaxError
Using the same name twice in the same parameter list (in a method parameter list, block parameter list, and lambda literal parameter list) is a SyntaxError:
def foo(a, a) end
# duplicated argument name (SyntaxError)
foo {|a, a|}
# duplicated argument name (SyntaxError)
-> (a, a) {}
# duplicated argument name (SyntaxError)
but _a or _ are valid:
def foo(_a, _a, _, _) end
foo {|_a, _a, _, _|}
-> (_a, _a, _, _) {}
Last result in IRb
There is a third usage of _ specifically in IRb which has nothing to do with the above: in IRb, the local variable _ is automatically assigned the value of the last expression that was evaluated in the current IRb session. But this is purely a feature of IRb and has nothing to do with Ruby.
Treatment in linters / style-checkers / static analyzers
The default rulesets in many linters, style-checkers, and static analyzers forbid unused parameters and local variables, on the assumption that this usually indicates a typo, a programming error, or leftover code from a refactoring. Similar to Ruby itself, they usually do allow this for variables and parameters starting with _.
This has nothing to do with the Ruby language itself, though, it is a matter of the Ruby community, more precisely, the developers of those tools following the majority usage within the community.
In this case, underscore will allow you to skip elements you do not need.
In other cases _ equals last output.
$ irb
>> 2*3
=> 6
>> _ + 7
=> 13
>> _
=> 13
Related
What sense does the whitespace between a function name and the left parenthese make?
foo=(x,y)->x*y
foo(1,2) # ok
foo (1,2) # not ok
The last line above gives an error: unexpected , .
In Coffeescript you can invoke a function which takes arguments with or without parenthesis:
foo(1,2)
foo 1, 2
If you have a space, then it well interpret whatever follows on the same line as the arguments. Let's take the example of another function bar which only takes one argument:
bar = (x) -> x * x
You could call this with a space before the parenthesis:
bar (2)
# ---> 4
This is because the parenthesis in Coffeescript (or Javascript) can be used to wrap an expression as well as invoke a function. Common examples are in if statements or for complex conditional / mathematical expressions. In the case of bar (2), the contents of the expression are evaluated simply to 2 (same as if you typed 2 into a coffee CLI). This is then passed to bar as if you called bar 2.
For your function foo which takes two arguments, it evaluates (1,2) as an expression. But , is not a valid operator so it throws an error. Same as if you typed 1,2 into a coffee CLI.
Sometimes if I've defined a a variable, for example
xyz="example"
and I'd like to refer back to xyz, I can either type xyz or #{xyz} in statements/loops etc.
My question is when do I use xyz and when do I use #{xyz}? And how do they differ?
#{} allows you to use any Ruby expression (not necessarily a variable) inside an interpolating quote (doubly-quoted strings, regular expressions...). It will evaluate the expression, convert the result to a string using the to_s method, then insert ("interpolate") the result into the string at that spot.
For example, if you have a string "Hello, apollo!" and want to replace the apollo with the contents of a variable, you could say "Hello, #{name}!".
You could even put a whole program inside a string:
"One plus two equals #{
def last_name_by_first_name(last_name)
People.find_by_last_name(last_name).first.first_name
end
find_by_last_name('Jack')
}!"
or
"#{a = 1} + #{b = 2} = #{a + b}"
(But please don't do that, it's a horrid way to write code. Sticking with variable look-ups and simple function calls should be enough for most purposes.)
Anywhere outside of a string (or other interpolating quote), #{} is an error.
In exercise 9 in the Learn Ruby the Hard Way book, I am asked to write the following:
formatter = "%{first} %{second} %{third} %{fourth}"
puts formatter % {first: 1, second: 2, third: 3, fourth: 4}
which just evaluates to
1 2 3 4
When searching around, I noticed that many people have written this instead:
formatter = "%s %s %s %s"
puts formatter % [1, 2, 3, 4]
I believe the latter example is from an older version of the book. Can someone explain to me what the differences are between the two examples?
The quick answer to that is that the %{} syntax allows you to pass in named arguments to be substituted into your string whereas the %s syntax only substitutes items in the order they are given.
You can do more things with the %{} version, for example if you have the same string you need to substitute in multiple times you could write it out like this:
string = "Hello %{name}, nice to meet you %{name}. Now I have said %{name} three times, I remember your name."
string % { :name => "Magnus" }
With the %s syntax, you would have had to write:
string = "Hello %s, nice to meet you %s. Now I have said %s three times, I remember your name."
string % ["Magnus", "Magnus", "Magnus"]
There are many other formats and ways to write substitutions for strings in Ruby. The full explanation can be found here in the Ruby documentation.
formatter = "%{first} %{second} %{third} %{fourth}"
and
formatter = "%s %s %s %s"
are essentially the same in that the formatting method will take values and substitute them into a string, however the first format string uses named placeholders vs. unnamed placeholders in the second.
This affects how you pass the values being substituted. The first accepts a hash of symbols, and uses the keys of that hash to identify which of the fields get that associated value. In the second, you pass an array, and the values are picked positionally from the array when being substituted into the format string.
The second is more common, and has been around for years, so you'll see it more often. The first, because it's newer isn't going to run on old Rubies, but has the advantage of resulting in a bit more readable format strings which is good for maintenance. Also, as #griffin says in his comment, the first also allows you to more easily repeat a value if necessary. You can do it when passing an array into the old-style format, but a hash would be more efficient memory-wise, especially for cases when you've got a lot of variables you're reusing.
Note: You'll see %{foo}f and %<foo>f. There is a difference in how the variable passed in is formatted, so be careful which you use:
'%<foo>f' % {:foo => 1} # => "1.000000"
'%{foo}f' % {:foo => 1} # => "1f"
I think the difference is too subtle and will cause problems for unaware developers. For more information, see the Kernel#sprintf documentation.
How to write multiline arithmetic properly in Ruby? Previously, i have tried something like y, then i realized there is something wrong with that code. I need to write multiline arithmetic due to my very long equation.
a = 5
b = 5
x = (a + b) / 2
puts x # 5, as expected
y = (
a
+ b
) /
2
puts y # 2, what happened?
The Ruby parser will assume a statement has ended if it looks like it has ended at an end of the line.
What you can to do prevent that is to leave the arithmetic operator just before a new line, like this:
a = 1
b = 2
c = a +
b
And you'll get the result you expect.
(
expr1
expr2
)
is actually, in Ruby, the same as
(expr1; expr2)
which just executes the first expression (for side effects) and returns the second one (also after evaluating it)
Try thinking about the "expectations" of the interpreter, and remember that in ruby EVERYTHING is an expression (which means that everything evaluates to some value, even constructs that in other languages are considered "special", like if-then-elses, loops, etcettera).
So:
y = ( #1
a #2
+ b #3
) / #4
2 #5
At line 1 we start the declaration of a variable, and the line ends with an open (pending) parenthesis. The interpreter expects the rest of the definition, so it proceeds to the next line looking for a VALUE to assign to the var y.
At line 2, the interpreter finds the variable a, but no enclosing parenthesis. It evaluates a, which has value 5, and since the line 2 is a perfectly-valid expression, the interpreter understands that this expression is finished (since in Ruby a newline OFTEN means end-of-expression indicator).
So up to now it has produced a value 5, but the only expectation it still has is that it must match the enclosing parenthesis.
If after that the interpreter had found the enclosing parenthesis, it would have assigned the value of a (i.e. 5) to the parenthesis expression (because everything must have a value, and the last value produced will be used).
When the interpreter reaches line 3, it finds another perfectly-valid ruby expression, + b. Since + 5 (5 being the value of variable b) is a VALID integer declaration in ruby, the interpreter sees it as standalone, not at all related to the previous 5 evaluated for the variable a (remember, it had no other expectation, except the one for the parenthesis).
In short, it throws away the value obtained for a, and uses only the value obtained with + b. In the next line it finds the enclosing parenthesis, and so the parenthesis-expression gets assigned the last produced value, which is a 5 produced by the expression + b.
Since on line 4 the interpreter finds a /, it (correctly) understands it as the division method of an integer, since it has produced an integer up to now (the int 5)! This creates the expectation for possible arguments of the method, which it finds on line 5. The resulting evaluated expression is y = 5 / 2, which equals 2 in integer division. So, basicaly, here is what the interpreter did:
y = ( # Ok, i'm waiting for the rest of the parenthesis expression
a # cool, a has value 5, if the parenthesis ends here, this is the value of the expr.
+ b # Oh, but now I found + b, which has value + 5, which evaluates to 5. So now this is the last value I have evaluated.
) / # Ok, the parenthesis have been closed, and the last value I had was a 5. Uow, wait, there is a slash / there! I should now wait for another argument for the / method of the 5 I have!
2 # Found, let's make y = 5 / 2 = 2!
The problem here is that on line #2, you should have left an expectation for the interpreter (exactly as you left on line 4 with the / method), which you did not!
The answer of #MaurĂcio Linhares suggests exactly this:
y = (
a +
b
) /
2
By moving the + method to the end of the line 2, you tell the interpreter that your expression is still not complete! So it keeps the expectation and proceeds to line #3 to find the right operand of the expression (or, more precisely in Ruby, an argument for the + method :D).
The same works with string concatenation:
# WRONG, SINCE + "somestring" is not a valid stand-alone expression in ruby
str = "I like to"
+ " move it!"
# NoMethodError: undefined method `+#' for " move it!":String
# CORRECT, by leaving the + sign as last statement of the first line, you
# keep the 'expectation' of the interpreter for the next
# argument of the + method of the string object "I like to"
str = "I like to" +
" move it!"
# => "I like to move it!"
The difference is that in your code there were no error thrown, since + b is actually a valid expression.
I hope my answer was useful on giving you some intuition on WHY it was not working as expected, sorry if I'm not concise :)
I came across a bit of an oddity (am using Ruby 1.9.1). Case scenario being:
class D
...
def self.d6
1+rand(6)
end
...
end
v = D::d6+2 # fine and dandy
v = D::d6 +2 # in `d6': wrong number of arguments (1 for 0) (ArgumentError)
v = D::d6 + 2 # fine and dandy
Why the "+2" in second case is treated as being "positive 2" and not an "addition of 2"?
The + same as the - in ruby are overloaded in order to make the syntax look nice.
When there is no space the Ruby parser recognizes the + as the method which is called on the result of d6 which is an Integer.
Same goes for the version with space before and after the +.
However: In the operator precedence in Ruby + as a unary operator is defined before + as a binary operator (as is often the case in other languages as well).
Therefore if there is a space before the + but not after it, the Ruby Parser will recognize it as d6(+2) which fits the error message.