Why is multiplication not always commutative in Ruby? - 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"

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.

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.

The commutative property of multiplication in Ruby

In ruby, I was messing around in the irb and found two code samples that should work the same but don't
"a" * 4 #this is "aaaa"
4 * "a" #this is "String can't be coerced into a Fixnum"
Doesn't this violate the commutative property of multiplication?
It does violate the commutative property, but that's not necessarily a problem, as the commutative property applies to the complex complex numbers in math. The reason "a" * 4 is not commutative in Ruby, as in most programming languages, is because a given type defines how it handles operators. So you could override the * operator for the String and Fixnum class (but that's a VERY VERY bad idea in practice):
class String
def *(other)
if other.is_a?(Numeric)
puts "The method was called on an instance of String"
end
end
end
class Fixnum
def *(other)
if other.is_a?(Numeric)
puts "The method was called on an instance of Fixnum"
end
end
end
So if you were to call
"a" * 4
Then it would print "The method was called on an instance of String" because that is equivalent to "a".*(4)
But this:
4 * "a"
Would print "The method was called on an instance of Fixnum" because 4 * "a" is equivalent to 4.*("a")
Here is a good article on operator overloading in Ruby.
Interesting side note: the commutative property actually doesn't apply to all numbers in math, the Quaterions and the Octonions both are not commutative.
Edit
If you wanted to, you could make the * operator commutative (but that would be a bad idea). You could then define * to swap the callee and the argument like such:
class Fixnum
def *(other)
other * self
end
end
That way, when ever you have 4 * "a" it would actually do this: "a" * 4. This would still work even if String#* was later redefined. Monkey patching can often be useful, but in this case it's a terrible idea, I don't recommend doing this, it's just a cool proof of concept.
"a" * 4 # repeat 'a' 4 times
4 * "a" # multiply 4 times the string 'a'
It's not multiplication unless two numbers are involved.
In Ruby, everything is an object. "a" is an object of class String, whereas 4 is an object of class Fixnum. So even numbers are objects.
And objects can have methods.
4 has a method called * that takes a number as an argument and multiplies 4 by that number. This method doesn't accept a string as an argument; it will unsuccessfully try to coerce the string to a number. (That's what explains your error message.)
"a" has a completely different method called * that takes a number as an argument. This method repeats the string multiple times.
Therefore:
4.*(4) # =>16
"a".*(4) # => "aaaa"
Ruby also lets you use a more succinct syntax for the * methods:
4 * 4 # =>16
"a" * 4 # => "aaaa"
But it's just a different way of writing the same thing.
No, it's a combination of precedence an the fact that they are both objects. What you are effectively doing in the 2nd version is 4.*("a"). Calling method '*' with parameter "a" on the Fixnum instance with value 4. So the String "a" cannot be coerced.

I have Integers in an array that I need converted to strings

When I type
digicollect=[]
digicollect[0]=2
I get 2 when I type in digicollect in the irb.
Also, when I type in
"Hello" * 2
I get "HelloHello"
But if I type in
2 * "Hello"
it doesn't work.
"hello" * digicollect
doesn't work.
but
"hello" * digicollect[0]
does work.
Why?
Everything in ruby is an object, and even multiplications are just method calls.
"Hello" * 2 is the same as "Hello".*(2)
So when you get an error you should ask yourself: Do the left hand side really have the multiplication method and will it accept the right hand side as an argument?
digicollect = []
digicollect[0] = 2
Let us check what kind of objects we have:
p digicollect.class #=> Array
p digicollect[0].class #=> Fixnum
p 2.class #=> Fixnum
p "Hello".class #=> String
Now if we go into the docs for the *-method we find what each class expect:
http://ruby-doc.org/core-2.1.0/String.html#method-i-2A
http://ruby-doc.org/core-2.1.0/Array.html#method-i-2A
http://ruby-doc.org/core-2.1.0/Fixnum.html#method-i-2A
In there we find what will happen:
String expects an Integer. (num of times to repeat string)
Array expects an Integer or a String. (to repeat array x times or to join using string)
Fixnum expects an Numeric. (For simple multiplication)
Thus when you write "hello" * digicollect you are trying to call the multiplication method of a sting and pass it an Array, and the method simply do not know how to handle it (it will only accept Integers), that is why you get the error.
I should preface this by saying I don't get 2 when I type digicollect in irb ... I get [2]. This is a single element array with a value of 2. That's very different from the integer value 2.
String has no * operator for an array argument, and number has no * operator with a string argument. However, String does have * with a number argument, and digicollect[0] access the numeric value of that array element.
digicollect itself is not numeric, that's why you can't 'multiply' by it. It contains numbers, though, which is why "hello" * digicollect[0] works.
As for the 2 * "Hello" case, I believe that's a syntactic thing about the language - The string must come first and the integer second.

Please explain this method

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.

Resources