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.
Related
I'm practicing a Ruby program for 2D coordinate operations. Among them, the writing of def +(other) and def -(other) confuses me. I have the following three questions:
Why is the method name equal to the operator name?
Where are the parameters received? Passed from where?
Why is the parameter other called other, and what is its value and
transmission process?
This is code
class Point
attr_accessor :x, :y
def initialize(x=0, y=0)
#x, #y = x, y
end
def inspect # p印出(x, y)
"(#{x}, #{y})"
end
def +(other)
self.class.new(x + other.x, y + other.y)
end
def -(other)
self.class.new(x - other.x, y - other.y)
end
end
point0 = Point.new(3, 6)
point1 = Point.new(1, 8)
p point0
p point1
p point0 + point1
p point0 - point1
it will eventually print
(3, 6)
(1, 8)
(4, 14)
(2, -2)
Why is the method name equal to the operator name?
Why not? Why should the symbol used to define the operator not be the symbol used to call it? That's how we do it for every other method, after all: if I want to call foo, I define def foo.
The Language designers could have chosen any arbitrary name. But it just makes sense to have the name of the method be the same symbol that you use to call it. Can you imagine the confusion if the language designers had chosen, for example, the symbol - for the name of the method which corresponds to the + operator?
Other programming languages make different choices. For example, in C++, the name of the function corresponding to the + operator is operator+. In Python, the name of the method corresponding to the + operator is __add__. (More precisely, when encountering the expression a + b, Python will first try calling a.__add__(b) and if that is not implemented by a, then it will try the "reverse add" b.__radd__(a).)
In C#, there is no method name which corresponds to the operator, rather, there is an operator keyword followed by the symbol corresponding to the operator.
If you want to know all the nitty-gritty details about how operator expressions are evaluated in Ruby, I recommend checking out Section 11.4.3 Unary operator expressions and Section 11.4.4 Binary operator expressions of the ISO/IEC 30170:2012 Information technology — Programming languages — Ruby specification.
Where are the parameters received? Passed from where?
It's not quite clear what you mean by this. A parameter is kind of like a "hole" or a placeholder in the method definition. This "hole" then gets filled in with an argument when you actually call the method. For example, here:
def foo(a, b) a + b end
a and b are parameters (more precisely, mandatory positional parameters, they are mandatory because you have to pass an argument for them and they are positional because which argument gets bound to which parameter in the parameter list depends on the position of the argument in the argument list). You don't actually know what the result of this method will be because you don't know what a and b are. They are placeholders for values that will be filled in when you call the method:
foo(2, 3)
Here, 2 and 3 are arguments (more precisely, positional arguments). The argument 2 gets bound to the parameter a because 2 is the first positional argument in the argument list and a is the first positional parameter in the parameter list. The argument 3 gets bound to the parameter b because 3 is the second positional argument in the argument list and b is the second positional parameter in the parameter list.
So, the code that gets ultimately executed for this particular method call is (replacing a with 2 and b with 3):
2 + 3
Please note: this is a simplified explanation. The mental model of replacing every occurrence of the parameter in the method definition body with the argument expression is a good first approximation, but it is not actually what Ruby does. In particular, that mental model I just described corresponds to the call-by-name evaluation strategy, whereas Ruby actually uses a special case of the call-by-value evaluation strategy called call-by-object-sharing.
You can observe the difference in this code:
def bar(a) a + a end
bar((puts "Hello"; 23))
# Hello
#=> 46
In the "replace every occurrence of the parameter with the argument expression" mental model which corresponds to call-by-name, the code would look like this:
(puts "Hello"; 23) + (puts "Hello"; 23)
# Hello
# Hello
#=> 46
and Hello would be printed twice.
However, with call-by-value and call-by-object-sharing, the argument expression gets evaluated before calling the method and the result of that evaluation gets passed in, so the actual code execution looks more like this:
__fresh_variable_with_unspeakable_name__ = (puts "Hello"; 23)
# Hello
__fresh_variable_with_unspeakable_name__ + __fresh_variable_with_unspeakable_name__
#=> 46
If you want to know all the nitty-gritty details about how method arguments are evaluated in Ruby, I recommend checking out Section 11.3 Method invocation expressions, in particular Section 11.3.1 General description and Section 11.3.2 Method arguments of the ISO/IEC 30170:2012 Information technology — Programming languages — Ruby specification.
There is also some (unfortunately incomplete) information to be found in The Ruby Spec Suite aka ruby/spec, in particular in language/def_spec.rb and language/method_spec.rb.
Why is the parameter other called other, and what is its value and
transmission process?
The parameter other is called other because that is what the author of that piece of code chose to call it. They could have called it a or b or x or y or foo or bar or i_dont_have_the_slightest_idea_what_to_call_this_parameter_so_i_am_just_choosing_something_totally_random. If you want to know why the author of that piece of code chose to call it other, you would have to ask the author of that piece of code.
other is a somewhat popular name for the "other" operand of a binary operator definition, not just in Ruby, as you can see for example in the Python documentation as well. It does make sense if you read it out loud: in an Object-Oriented Programming Language like Ruby or Python, where operators are interpreted as being sent to one of the operands, one of the two operands of a binary operator will always be self or this and the "other" operand will be … well … the "other" operand. So, naming it other is just natural. In Ruby, this is codified in some Style Guides, for example the Rubocop Ruby Style Guide.
I want to define singleton method to every integer value (object) . but i am getting error while applying singleton method.
RubyDoc says There is effectively only one Fixnum object instance for any given integer value . what does this mean ?? how it is different from other normal classes?? i am not able to interpret this line.
I want to define singleton method to every integer value (object)
This is contradictory. The singleton class is for when you want something to apply to a single object. You want to define something for every integer object, so the singleton class is not an appropriate tool. Just use the normal class
class Integer
def foobar
"hey"
end
end
3.foobar
# "hey"
If you could modify the singleton class of 3, then there would be some behaviors that only apply to the number 3 and no other number. There is no technical reason to prevent that, but trust me that it's a good thing that you can't.
There is effectively only one Fixnum object instance for any given integer value
This is talking about something else. Notice the difference:
x = []
y = []
x == y # true
x.object_id == y.object_id # false!
x = 3
y = 3
x == y # true
x.object_id == y.object_id # true!
x.object_id == 5.object_id # false
Unlike most other objects, equal fixnums are identical objects. 3 and 5 are two different instances of Fixnum, but it is impossible to have two different instances of Fixnum that are both 3. Every 3 is the same. Again, this is not a technical necessity but more of a convenience for how most programmers think about numerical data.
It means that whenever you access some Fixnum, such as the number 1, you’re always treating with the same “instance”, this is mostly an implementation detail which ruby uses to optimize numbers.
The Integer class is frozen by default:
1.frozen?
=> true
There only ever exists one instance of any Integer object. You don't have to do anything special to enable this. In other words, the optimization you are trying to apply is built into 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"
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.
It is said that when we have a class Point and knows how to perform point * 3 like the following:
class Point
def initialize(x,y)
#x, #y = x, y
end
def *(c)
Point.new(#x * c, #y * c)
end
end
point = Point.new(1,2)
p point
p point * 3
Output:
#<Point:0x336094 #x=1, #y=2>
#<Point:0x335fa4 #x=3, #y=6>
but then,
3 * point
is not understood:
Point can't be coerced into Fixnum (TypeError)
So we need to further define an instance method coerce:
class Point
def coerce(something)
[self, something]
end
end
p 3 * point
Output:
#<Point:0x3c45a88 #x=3, #y=6>
So it is said that 3 * point is the same as 3.*(point). That is, the instance method * takes an argument point and invoke on the object 3.
Now, since this method * doesn't know how to multiply a point, so
point.coerce(3)
will be called, and get back an array:
[point, 3]
and then * is once again applied to it, is that true?
Now, this is understood and we now have a new Point object, as performed by the instance method * of the Point class.
The question is:
Who invokes point.coerce(3)? Is it Ruby automatically, or is it some code inside of * method of Fixnum by catching an exception? Or is it by case statement that when it doesn't know one of the known types, then call coerce?
Does coerce always need to return an array of 2 elements? Can it be no array? Or can it be an array of 3 elements?
And is the rule that, the original operator (or method) * will then be invoked on element 0, with the argument of element 1? (Element 0 and element 1 are the two elements in that array returned by coerce.) Who does it? Is it done by Ruby or is it done by code in Fixnum? If it is done by code in Fixnum, then it is a "convention" that everybody follows when doing a coercion?
So could it be the code in * of Fixnum doing something like this:
class Fixnum
def *(something)
if (something.is_a? ...)
else if ... # other type / class
else if ... # other type / class
else
# it is not a type / class I know
array = something.coerce(self)
return array[0].*(array[1]) # or just return array[0] * array[1]
end
end
end
So it is really hard to add something to Fixnum's instance method coerce? It already has a lot of code in it and we can't just add a few lines to enhance it (but will we ever want to?)
The coerce in the Point class is quite generic and it works with * or + because they are transitive. What if it is not transitive, such as if we define Point minus Fixnum to be:
point = Point.new(100,100)
point - 20 #=> (80,80)
20 - point #=> (-80,-80)
Short answer: check out how Matrix is doing it.
The idea is that coerce returns [equivalent_something, equivalent_self], where equivalent_something is an object basically equivalent to something but that knows how to do operations on your Point class. In the Matrix lib, we construct a Matrix::Scalar from any Numeric object, and that class knows how to perform operations on Matrix and Vector.
To address your points:
Yes, it is Ruby directly (check calls to rb_num_coerce_bin in the source), although your own types should do too if you want your code to be extensible by others. For example if your Point#* is passed an argument it doesn't recognize, you would ask that argument to coerce itself to a Point by calling arg.coerce(self).
Yes, it has to be an Array of 2 elements, such that b_equiv, a_equiv = a.coerce(b)
Yes. Ruby does it for builtin types, and you should too on your own custom types if you want to be extensible:
def *(arg)
if (arg is not recognized)
self_equiv, arg_equiv = arg.coerce(self)
self_equiv * arg_equiv
end
end
The idea is that you shouldn't modify Fixnum#*. If it doesn't know what to do, for example because the argument is a Point, then it will ask you by calling Point#coerce.
Transitivity (or actually commutativity) is not necessary, because the operator is always called in the right order. It's only the call to coerce which temporarily reverts the received and the argument. There is no builtin mechanism that insures commutativity of operators like +, ==, etc...
If someone can come up with a terse, precise and clear description to improve the official documentation, leave a comment!
I find myself often writing code along this pattern when dealing with commutativity:
class Foo
def initiate(some_state)
#...
end
def /(n)
# code that handles Foo/n
end
def *(n)
# code that handles Foo * n
end
def coerce(n)
[ReverseFoo.new(some_state),n]
end
end
class ReverseFoo < Foo
def /(n)
# code that handles n/Foo
end
# * commutes, and can be inherited from Foo
end