Please explain this method - ruby

I have a question regarding the stars in this method:
def multiplies_array(*numbers)
numbers.inject(1, :*)
end
What is the meaning of the star in the argument list (*numbers)?
And what is the meaning of the star after the colon (1, :*)?

The first star is the splat operator. In this case it "collects" all parameters given to multiplies_array into a single Array.
Calling it like this with four parameters...
multiplies_array 1, 2, 3, 4
... gives you a single array with four elements in the method.
This is equivalent to:
def multiplies_array(numbers) # Without splat operator
end
multiplies_array [1, 2, 3, 4]
The second star is a little confusing. Here the the multiplication operator is meant:
The : denotes a symbol. All Enumerable methods allow passing a symbol as a shortcut. It means: "Call the method with this name".
In other words the * method is applied to each item in the numbers array. Without the symbol shortcut that line would look like:
numbers.inject(1) { |result, number| result * number) }
I hope this sheds a little light on all that Ruby magic :)

See the documentation for inject.
It "combines all elements of enum by applying a binary operation, specified by a block or a symbol that names a method or operator."
So, the :* is specifying the multiplication operator in numbers.inject(1, :*) The :* specifies it as a symbol but you could do numbers.inject(1, '*') as well. Using a symbol is more idiomatic.

Related

How does Ruby Array #count handle multiple block arguments

When I execute the following:
[[1,1], [2,2], [3,4]].count {|a,b| a != b} # => 1
the block arguments a, b are assigned to the first and the second values of each inner array respectively. I don't understand how this is accomplished.
The only example given in the documentation for Array#count and Enumerable#count with a block uses a single block argument:
ary.count {|x| x % 2 == 0} # => 3
Just like assignments, there's a (not-so-) secret shortcut. If the right-hand-side is an array and the left-hand-side has multiple variables, the array is splatted, so the following two lines are identical:
a, b, c = [1, 2, 3]
a, b, c = *[1, 2, 3]
While not the same thing, blocks have something in the same vein, when the yielded value is an array, and there are multiple parameters. Thus, these two blocks will act the same when you yield [1, 2, 3]:
do |a, b, c|
...
end
do |(a, b, c)|
...
end
So, in your case, the value gets deconstructed, as if you wrote this:
[[1,1], [2,2], [3,4]].count {|(a,b)| a != b} # => 1
If you had another value that you are passing along with the array, you would have to specify the structure explicitly, as the deconstruction of the array would not be automatic in the way we want:
[[1,1], [2,2], [3,4]].each.with_index.count {|e,i| i + 1 == e[1] }
# automatic deconstruction of [[1,1],0]:
# e=[1,1]; i=0
[[1,1], [2,2], [3,4]].each.with_index.count {|(a,b),i| i + 1 == b }
# automatic deconstruction of [[1,1],0], explicit deconstruction of [1,1]:
# a=1; b=1; i=0
[[1,1], [2,2], [3,4]].each.with_index.count {|a,b,i| i + 1 == b }
# automatic deconstruction of [[1,1],0]
# a=[1,1]; b=0; i=nil
# NOT what we want
I have looked at the documentation for Array.count and Enumerable.count and the only example given with a block uses a single block argument ...
Ruby, like almost all mainstream programming languages, does not allow user code to change the fundamental semantics of the language. In other words, you won't find anything about block formal parameter binding semantics in the documentation of Array#count, because block formal parameter binding semantics are specified by the Ruby Language Specification and Array#count cannot possibly change that.
What I don't understand is how this is accomplished.
This has nothing to do with Array#count. This is just standard block formal parameter binding semantics for block formal parameters.
Formal parameter binding semantics for block formal parameters are different from formal parameter binding semantics for method formal parameters. In particular, they are much more flexible in how they handle mismatches between the number of formal parameters and actual arguments.
If there is exactly one block formal parameter and you yield more than one block actual argument, the block formal parameter gets bound to an Array containing the block actual arguments.
If there are more than one block formal parameters and you yield exactly one block actual argument, and that one actual argument is an Array, then the block formal parameters get bound to the individual elements of the Array. (This is what you are seeing in your example.)
If you yield more block actual arguments than the block has formal parameters, the extra actual arguments get ignored.
If you pass fewer actual arguments than the block has formal parameters, then those extra formal parameters are defined but not bound, and evaluate to nil (just like defined but unitialized local variables).
If you look closely, you can see that the formal parameter binding semantics for block formal parameters are much closer to assignment semantics, i.e. you can imagine an assignment with the block formal parameters on the left-hand side of the assignment operator and the block actual arguments on the right-hand side.
If you have a block defined like this:
{|a, b, c|}
and are yielding to it like this:
yield 1, 2, 3, 4
you can almost imagine the block formal parameter binding to work like this:
a, b, c = 1, 2, 3, 4
And if, as is the case in your question, you have a block defined like this:
{|a, b|}
and are yielding to it like this:
yield [1, 2]
you can almost imagine the block formal parameter binding to work like this:
a, b = [1, 2]
Which of course, as you well know, will have this result:
a #=> 1
b #=> 2
Fun fact: up to Ruby 1.8, block formal parameter binding was using actual assignment! You could, for example, define a constant, an instance variable, a class variable, a global variable, and even an attribute writer(!!!) as a formal parameter, and when you yielded to that block, Ruby would literally perform the assignment:
class Foo
def bar=(value)
puts "`#{__method__}` called with `#{value.inspect}`"
#bar = value
end
attr_reader :bar
end
def set_foo
yield 42
end
foo = Foo.new
set_foo {|foo.bar|}
# `bar=` called with `42`
foo.bar
#=> 42
Pretty crazy, huh?
The most widely-used application of these block formal parameter binding semantics is when using Hash#each (or any of the Enumerable methods with a Hash instance as the receiver). The Hash#each method yields a single two-element Array containing the key and the value as an actual argument to the block, but we almost always treat it as if it were yielding the key and value as separate actual arguments. Usually, we prefer writing
hsh.each do |k, v|
puts "The key is #{k} and the value is #{v}"
end
over
hsh.each do |key_value_pair|
k, v = key_value_pair
puts "The key is #{k} and the value is #{v}"
end
And that is exactly equivalent to what you are seeing in your question. I bet you have never asked yourself why you can pass a block with two block formal parameters to Hash#each even though it only yields a single Array? Well, this case is exactly the same. You are passing a block with two block formal parameters to a method that yields a single Array per iteration.

Why is multiplication not always commutative in Ruby?

If x is a non-integer, I get this result:
x = "a"
x * 6 #=> aaaaaa
6 * x #=> TypeError: String can't be coerced into Fixnum
whereas if x is an integer:
x = 6
x * 6 #=> 36
6 * x #=> 36
It's strange that the operand order in multiplication matters if x is a non-integer, and not if x is an integer. Can someone explain what the rational is behind this? When x is a string, why must variable x precede the * operator to avoid raising an error?
You have a typo in your latter snippet: it should start with x = 6 (without quotes.)
Everything in Ruby is an object, including instances of String, Integer, even nil which is [the only] instance of NilClass.
That said, there is no just an operator *. It’s a plain old good method, declared on different classes, that is called by the operator * (thanks #SergioTulentsev for picky wording comment.) Here is a doc for String#*, other you might find yourself. And "a" * 6 is nothing else, than:
"a".*(6)
You might check the above in your console: it’s a perfectly valid Ruby code. So, different classes have different implementations of * method, hence the different results above.
You are trying three patterns here:
a. string * numeric
b. numeric * string
c. numeric * numeric
The behavior of a method and what arguments are required primarily depends on what is on the left side of the method (* in this case), on which the method is defined. No method (including *) is commutative per se.
String#* requires the first argument to be a numeric, which a. satisfies, and Numeric#* requires the first argument to be a numeric, which c. satisfies, and b. does not.
You need to understand what the method * does.1. That depends on the method's receiver. For "cat".*(3), "cat" is *'s receiver. For 1.*(3) (which, as explained later, can be written, 1*3) 1 is *'s receiver. The term "receiver" derives from OOP's concept of sending a message (method) to a receiver.
A method can be defined on an object (e.g., "cat" or 1) in one of two ways. The most common is that the method is an instance method defined on the receiver's class (e.g., * defined on "cat".class #=> String or 1.class #=> Integer. The second way, which is not applicable here, is that the method has been defined on the object's singleton class, provided the object has one. ("cat" has a singleton class but 1, being an immediate value, does not.)
When we see "cat".*(3), therefore, we look to the doc for String#* and conclude that
"cat".*(3) #=> "catcatcat"
For 1*(3), we look to Integer#*, which tells us that
1.*(3) #=> 3
Let's try another: [1,2,3].*(3), Because [1,2,3].class #=> Array we look to Array#* and conclude that
[1,2,3].*(3) #=> [1, 2, 3, 1, 2, 3, 1, 2, 3]
Note that this method has two forms, depending on whether its argument is an integer (as here) or a string. In the latter case
[1,2,3].*(' or ') #=> "1 or 2 or 3"
Many methods have different behaviors that depend on its arguments (and on whether an optional block is provided).
Lastly, Ruby allows us to use a shorthand with these three methods (and certain others with names comprised of characters that are not letters, numbers or underscores.):
"cat"*3 #=> "catcatcat"
"cat" * 3 #=> "catcatcat"
1*3 #=> 3
[1,2,3] * 3 #=> [1, 2, 3, 1, 2, 3, 1, 2, 3]
This shorthand is generally referred to as "syntactic sugar".
1 Ruby's method names are not restricted to words, such as "map", "upcase"
and so on. "*", "~", "[]" and "[]=", for example, are valid method names"

How does ruby unpack arguments passed into Proc?

a_proc = Proc.new {|a,b,*c| p c; c.collect {|i| i*b }}
puts a_proc[2,2,4,3]
Code above is pretty intuitive according to https://ruby-doc.org/core-2.2.0/Proc.html, a_proc[2,2,4,3] is just a syntax sugar for a_proc.call(2,2,4,3) to hide “call”
But the following (works well) confused me a lot
a=[2,2,4,3]
puts a_proc.call(a)
puts a_proc.call(*a)
It seems very different from a normal function call, cause it doesn't check the number arguments passed in.
However, as expected the method calling semantics will raise an error if using parameters likewise
def foo(a,b,*c)
c.collect{|i| i*b}
end
foo([1,2,3,4]) #`block in <main>': wrong number of arguments (given 1, expected 2+) (ArgumentError)
foo(*[1,2,3,4]) #works as expected
I do not think such an inconsistency as a design glitch, so any insights on this will be appreciated.
Blocks use different semantics than methods for binding arguments to parameters.
Block semantics are more similar to assignment semantics than to method semantics in this regard. In fact, in older versions of Ruby, blocks literally used assignment for parameter binding, you could write something like this:
class Foo; def bar=(val) puts 'setter called!' end end
some_proc = Proc.new {|$foo, #foo, foo.bar|}
some_proc.call(1, 2, 3)
# setter called!
$foo #=> 1
#foo #=> 2
Thankfully, this is no longer the case since Ruby 1.9. However, some semantics have been retained:
If a block has multiple parameters but receives only a single argument, the argument will be sent a to_ary message (if it isn't an Array already) and the parameters will be bound to the elements of the Array
If a block receives more arguments than it has parameters, it ignores the extra arguments
If a block receives fewer arguments than it has parameters, the extra parameters are bound to nil
Note: #1 is what makes Hash#each work so beautifully, otherwise, you'd always have to deconstruct the array that it passes to the block.
In short, block parameters are bound much the same way as with multiple assignment. You can imagine assignment without setters, indexers, globals, instance variables, and class variables, only local variables, and that is pretty much how parameter binding for blocks work: copy&paste the parameter list from the block, copy&paste the argument list from the yield, put an = sign in between and you get the idea.
Now, you aren't actually talking about a block, though, you are talking about a Proc. For that, you need to know something important: there are two kinds of Procs, which unfortunately are implemented using the same class. (IMO, they should have been two different classes.) One kind is called a lambda and the other kind is usually called a proc (confusingly, since both are Procs).
Procs behave like blocks, both when it comes to parameter binding and argument passing (i.e. the afore-described assignment semantics) and also when it comes to the behavior of return (it returns from the closest lexically enclosing method).
Lambdas behave like methods, both when it comes to parameter binding and argument passing (i.e. strict argument checking) and also when it comes to the behavior of return (it returns from the lambda itself).
A simple mnemonic: "block" and "proc" rhyme, "method" and "lambda" are both Greek.
A small remark to your question:
a_proc[2,2,4,3] is just a syntax sugar for a_proc.call(2,2,4,3) to hide “call”
This is not syntactic sugar. Rather, Proc simply defines the [] method to behave identically to call.
What is syntactic sugar is this:
a_proc.(2, 2, 4, 3)
Every occurrence of
foo.(bar, baz)
gets interpreted as
foo.call(bar, baz)
I believe what might be confusing you are some of the properties of Procs. If they are given a single array argument, they will automatically splat it. Also, ruby blocks in general have some interesting ways of handling block arguments. The behavior you're expecting is what you will get with a Lambda. I suggest reading Proc.lambda? documentation and be careful when calling a ruby block with an array.
Now, let's start with the splat operator and then move to how ruby handles block arguments:
def foo(a, b, *c)
c.map { |i| i * b } # Prefer to use map alias over collect
end
foo([1, 2, 3, 4]) # `block in <main>': wrong number of arguments (given 1, expected 2+) (ArgumentError)
foo(*[1, 2, 3, 4]) # works as expected
So in your argument error, it makes sense: def foo() takes at least two arguments: a, b, and however many with *c. The * is the splat operator. It will turn an array into individual arguments, or in the reverse case here, a variable amount of arguments into an array. So when you say foo([1,2,3,4]), you are giving foo one argument, a, and it is [1,2,3,4]. You are not setting b or *c. What would work is foo(1, 1, 1, 2, 3, 4]) for example because you are setting a, b, and c. This would be the same thing: foo(1, 1, *[1,2,3,4]).
Now foo(*[1, 2, 3, 4]) works as expected because the splat operator (*) is turning that into foo(1, 2, 3, 4) or equivalently foo(1, 2, *[3, 4])
Okay, so now that we have the splat operator covered, let's look back at the following code (I made some minor changes):
a_proc = Proc.new { |a, b, *c| c.map { |i| i * b }}
a = [1, 2, 3, 4]
puts a_proc.call(a)
puts a_proc.call(*a)
Remember that if blocks/procs are given a single array argument they will automatically splat it. So if you have an array of arrays arrays = [[1, 1], [2, 2], [3, 3]] and you do arrays.each { |a, b| puts "#{a}:#{b}" } you are going to get 1:1, 2:2, and 3:3 as the output. As each element is passed as the argument to the block, it sees that it is an array and splats it, assigning the elements to as many of the given block variables as it can. Instead of just putting that array in a such as a = [1, 1]; b = nil, you get a = 1; b = 1. It's doing the same thing with the proc.
a_proc.call([1, 2, 3, 4]) is turned into Proc.new { |1, 2, [3, 4]| c.map { |i| i * b }} and will output [6, 8]. It splits up the arguments automatically it's own.

Understanding `array.map(&:method)` [duplicate]

This question already has answers here:
What does map(&:name) mean in Ruby?
(17 answers)
Closed 6 years ago.
Why does:
[1,2,3,4,5].map(&:to_s) #=> ["1", "2", "3", "4", "5"]
work but:
[1,2,3,4,5].map(&:*(2))
throws an unexpected syntax error?
& is called the to_proc operator. It calls the to_proc method on the expression that follows it and then passes the resulting Proc to the method as a block.
In the case of &:to_s, :to_s is a Symbol, so it the operator calls Symbol#to_proc. The docs are a little garbled, but suffice it to say that these two expressions are more-or-less equivalent:
my_proc = :to_s.to_proc
my_proc = Proc.new {|obj| obj.to_s }
So the answer to the question "Why doesn't &:*(2) work?" is that the expression that follows the & operator, :*(2), isn't a valid Ruby expression. It makes about as much sense to the Ruby parser as "hello"(2).
There is, by the way, a way to do what you're trying to do:
[1,2,3,4,5].map(&2.method(:*))
# => [2, 4, 6, 8, 10]
In the above code, 2.method(:*) returns a reference to the * method of the object 2 as a Method object. Method objects behave a lot like Proc objects, and they respond to to_proc. However, the above isn't exactly equivalent—it does 2 * n rather than n * 2 (a distinction that doesn't matter if n is also a Numeric)—and it's not any more succinct or readable than {|n| n * 2 }, and so rarely worth the trouble.
Ampersand and object (&:method)
The & operator can also be used to pass an object as a block to a method, as in the following example:
arr = [ 1, 2, 3, 4, 5 ]
arr.map { |n| n.to_s }
arr.map &:to_s
Both the examples above have the same result. In both, the map method takes the arr array and a block, then it runs the block on each element of the array. The code inside the block runs to_s on each element, converting it from integers to strings. Then, the map method returns a new array containing the converted items.
The first example is common and widely used. The second example may look a bit cryptic at first glance. Let's see what's happening:
In Ruby, items prefixed with colon (:) are symbols. If you are not familiar with the Symbol class/data type, I suggest you Google it and read a couple of articles before continuing. All method names in Ruby are internally stored as symbols. By prefixing a method name with a colon, we are not converting the method into a symbol, neither are we calling the method, we are just passing the name of the method around (referencing the method). In the example above, we are passing :to_s, which is a reference to the to_s method, to the ampersand (&) operator, which will create a proc (by calling to_proc under the hood). The proc takes a value as an argument, calls to_s on it and returns the value converted into a string.
Although the :to_s symbol is always the same, when running the map loop, it will refer to the to_s method of the class corresponding to each array item. If we passed an array such as [ 21, 4.453, :foobar, ] to the map method, the to_s method of the Fixnum class would be applied (called) on the first item, the to_s method of the Float class would be applied to the second item and the to_s method of the Symbol class would be applied to the third item. This makes sense because we are not passing the actual to_s method to the ampersand operator, just its name.
Below is an example of creating a proc that takes an argument, calls a method on it and returns the result of the method.
p = :upcase.to_proc
p.call("foo bar")
Output:
=> "FOO BAR"
Let's review what is going on in arr.map &:to_s
At each iteration of map, one item of the array (an integer) is passed to &:to_s
The :to_s symbol (which is a reference to the to_s method) is passed to the & operator, which creates a proc that will take an argument (an array item), call to_s on the argument and return the value converted into string;
The map method returns a new array containing the strings "1", "2", "3", "4" and "5".

I'm learning Ruby and I don't clearly understand what :* means in inject(:*) [duplicate]

This question already has answers here:
How does this ruby injection magic work?
(3 answers)
Closed 7 years ago.
I'm writing a method for calculating the factorial of a number and I found something similar to this in my search.
def factorial(number)
(1..number).inject(:*) || 1
end
It works and I understand what the inject function is doing, but I don't clearly understand what the (:\*) part really means.
I know it must be a shorthand version of writing {|num, prod| num*prod}, but I would love a clear explanation. Thanks!!
:* is simply the method name for * of the method for inject to execute. If you look at the documentation for inject http://ruby-doc.org/core-2.2.2/Enumerable.html#method-i-inject
It states that
If you specify a symbol instead, then each element in the collection will be passed to the named method of memo. In either case, the result becomes the new value for memo. At the end of the iteration, the final value of memo is the return value for the method.
So taken that inject { |memo, obj| block }
The following are equal
ary = [1,2,3]
ary.inject(:*)
#=> 6
ary.inject { |memo, obj| memo.*(obj) }
#=> 6
Short explanation
:* is a symbol. Symbols are immutable strings. :* is like "*" except it's immutable.
In ruby, multiplication is a method invocation too. It's equivalent invoking the .*(second) method of the first multiplier with the second multiplier as an argument. In fact, you can type 3.*(4) instead of 3*4. 3*4 is just syntactic sugar as far as ruby is concerned.
Method invocation in ruby can be invoked by public_sending symbol messages to objects. 3.public_send(:*, 4) will also work just like 3*4.
The argument to inject is interpreted as what type of message should be public_senT, that is, what method should be invoked from the internals of the inject method.
Longer explanation
You can think of
[ 1, 2, 3, 4 ].inject(:*)
as injecting '*' between each adjacent pair of each enumerable object that inject is invoked on:
[ 1, 2, 3, 4 ].inject(:*) == 1 * 2 * 3 * 4
Of course 1 * 2 * 3 * 4 is equivalent to going from left to right, and applying :* on your running tally and the next number to get your next tally, and then returning the final tally.
module Enumerable
def inject_asterisk
tally = first
rest = slice(1, length - 1)
rest.each do |next_num|
tally = tally * next_num
end
return tally
end
end
[2, 3, 5].inject_asterisk #=> 30
You can generalize this by making the operation that combines the tally and next_number to get your next tally an argument function. Blocks in ruby serve basically as argument functions that always have a reserved spot.
module Enumerable
def inject_block(&block)
tally = first
rest = slice(1, length - 1)
rest.each do |next_num|
tally = block.call(tally, next_num)
end
return tally
end
end
[2, 3, 5].inject_block {|tally, next_num| tally + next_num } #=> 10
If your block is always going to be of the form
{|tally, next_num| tally.method_of_tally(next_num) }
as it is in this case (remember tally + next_num <==> tally.+(next_num) <==> tally.public_send(:+,next_num), you can decide to only pass :method_of_tally as the argument and imply the block.
module Enumerable
def my_inject(method_of_tally_symbol, &block)
if method_of_tally_symbol
block = Proc.new { |tally, next_num|
tally.public_send(method_of_tally_symbol, next_num)
}
end
tally = first
rest = slice(1, length - 1)
rest.each do |next_num|
tally = block.call(tally, next_num)
end
return tally
end
end
[2, 3, 5].my_inject(:+) #=> 10
It's all about extracting repeated patterns into reusable components so that you don't have to type as much.
It means symbol to proc and it's a shortcut. Typically you would write something like
array.map { |e| e.join }
with symbol to proc, the shorthand would be
array.map(&:join)
inject and reduce are similar, but you don't need the & in those cases
For example, if you have an array of numbers called numbers
To sum the numbers, you could do
numbers.inject(&:+)
or you could leave off the ampersand
numbers.inject(:+)
http://ruby-doc.org/core-2.2.2/Enumerable.html#method-i-inject
Inject is a method on enumerable that combines the elements of said enumerable using a symbol (as in your case) or a block (as in your proposed longhand).
For example:
(5..10).reduce(:*) is equivalent to (5..10).inject { |prod, n| prod + n }

Resources