Method named ***(other)


#1

Hi!

It’s several hours now that i’m trying to find out what’s special with
*** for a method name, without success :frowning:

I’m trying to add an element wise multiplication method to the Matrix
class. For this I created a collect2 method for Matrix similar to the
one in Vector as follows:

class Matrix
def collect2(other)
result = self.clone
(0…self.row_size).each {|rowi|
(0…self.column_size).each {|columni|
result[rowi,columni] = yield (self[rowi,columni],
other[rowi,columni])
}
}
result
end
def []=(i,j,v)
@rows[i][j] = v
end
end

And i would like now to add a method *** to Matrix such that we could
call matrix1 *** matrix2. Like:
m = Matrix[[1,2,3],[-1,-2,-3], [4,5,6]]
n = Matrix[[1,2,3],[7,8,9], [-1,-2,-3]]
m *** n
=> Matrix[[1, 4, 9], [-7, -16, -27], [-4, -10, -18]]

Now if I define this method as follows:
def **(other)
collect2(other) do |e1,e2|
if(e1 and e2)
e1
e2
end
end
end

I get the following error:
SyntaxError: compile error
(irb):550: parse error, unexpected tLPAREN, expecting ‘\n’ or ‘;’
def ***(other)
^
(irb):557: parse error, unexpected kEND, expecting $
from (irb):557
from :0

The same with def *** other works (I can define it without error).
But now a call to m *** n gives me:
SyntaxError: compile error
(irb):33: parse error, unexpected tSTAR
m *** n
^
from (irb):33
from :0

And m.*** n (notice the period after m) gives:
TypeError: Array can’t be coerced into Fixnum
from (irb):8:in *' from (irb):8:in
from (irb):24:in collect2' from (irb):23:ineach’
from (irb):23:in collect2' from (irb):22:ineach’
from (irb):22:in collect2' from (irb):6:in

from (irb):35
from :0

Whereas if I name the method with two stars only, i.e. def **(other), it
can be defined, and then m ** n gives the expected result.

I therefore have the following questions:

  • Why is it possible to define def *** other but not def ***(other) ?
  • What is the difference between m.*** n and m *** n (with and without
    period after m) ?
  • Why do I get an error with m.*** n (with period) but not with m ** n ?

I would greatly appreciate any answer of pointers to some information
sources (I tried but it is not easy to search for *** in a web search
engine :wink: )

Thanks a lot in advance for your help and advices!

Julien


#2

Julien G. wrote:

Hi!

It’s several hours now that i’m trying to find out what’s special with
*** for a method name, without success :frowning:

That should be your clue. There isn’t anything special about “***”,
whereas the infix operators that exist in Ruby that you can redefine
require special treatment by the interpreter. You can’t expand the set
of operators, and ‘***’ isn’t among them.

Vidar


#3

On 12/21/06, Julien G. removed_email_address@domain.invalid wrote:

of operators, and ‘***’ isn’t among them.
Ah, ok, thanks a lot. I understood why i could use ‘***’ as an infix
operator. But still, there shouldn’t be any difference between a call
like m.*** n and m.triple_star n… But it seems there is since
m.triple_star works and m.*** don’t.

I don’t get it.

The basic problem is that ** is right-associative, and * is
left-associative. The existing grammar can’t resolve the apparent
conflict.
Also, *** is unreadably nasty, so it’s good that you can’t name a
method that. :slight_smile:


#4

whereas the infix operators that exist in Ruby that you can redefine
The basic problem is that ** is right-associative, and * is
left-associative. The existing grammar can’t resolve the apparent
conflict.
Ah ok! I get it!!! :smiley: Thanks a lot!
Also, *** is unreadably nasty, so it’s good that you can’t name a
method that. :slight_smile:
:slight_smile:
I found it ok compared to ===. But if the interpreter can’t read it…


#5

of operators, and ‘***’ isn’t among them.
Ah, ok, thanks a lot. I understood why i could use ‘***’ as an infix
operator. But still, there shouldn’t be any difference between a call
like m.*** n and m.triple_star n… But it seems there is since
m.triple_star works and m.*** don’t.

I don’t get it.

Julien


#6

Julien G. wrote:

Ah, ok, thanks a lot. I understood why i could use ‘***’ as an infix
operator. But still, there shouldn’t be any difference between a call
like m.*** n and m.triple_star n… But it seems there is since
m.triple_star works and m.*** don’t.

I don’t get it.

Again, the only reason you can use a name like ‘**’ is that it’s one of
the predefined operators. You can’t just use any characters you want in
a method name - the only method names you can use “special” characters
like ‘*’ in are method names matching the specific operators you can
override.

I think your confusion probably stems from the fact that this parses
without errors:

def *** other
end

Hower, try to run this:

class Foo
def *** other
end
end

p Foo.new.methods.sort

This should print out a sorted list of methods of instances of Foo.
You’ll see “**” shows up as the first method. The reason is that “def
*** other” gets parsed as “def ** other" (note the space). "” in
this case is the “splat” operator, that indicates that “other” will
hold an arbitrary number of arguments in an array.

So you haven’t defined Foo#*, but Foo#.

Vidar

Vidar


#7

Vidar H. wrote:

Again, the only reason you can use a name like ‘**’ is that it’s one of

You’ll see “**” shows up as the first method. The reason is that “def
*** other” gets parsed as “def ** other" (note the space). "” in
this case is the “splat” operator, that indicates that “other” will
hold an arbitrary number of arguments in an array.

So you haven’t defined Foo#*, but Foo#.

Nice explanation! I was indeed misled by the fact that some operators
are actually implemented as methods. And therefore considered the
character ‘*’ as a standard one for a method…

As you might have guessed I’m a complete newbie to Ruby :wink:

Thank you again for those enlightenments!

Cheers,

Julien


#8

Julien G. wrote:

I found it ok compared to ===. But if the interpreter can’t read it…

That one’s ugly too – a word alias for it is in my bag of wishes.

T.


#9

On 12/21/06, Luciano R. removed_email_address@domain.invalid wrote:

Cheers,

Luciano

“operators” are only special in that the parser is built to recognize a
few
constructs, mainly the mathematical operators (+, -, /, *, etc). For the
programmer’s case, they are all methods on some object, and all methods
can
be overwritten. So

class A
def +(args)
end
end

class B
def *(args)
end
end

def /(args)
end

etc…

Always keep in mind this simple feature: 1 + 1 => 1.+(1) and you’ll
realize
that there really isn’t “operator overloading” in Ruby, everything is
just a
message.

Jason


#10

On 12/21/06, Vidar H. removed_email_address@domain.invalid wrote:

You can’t expand the set
of operators, and ‘***’ isn’t among them.

Thanks for the reply, Vidar.

Is there a way I can ask irb to list all the operators which can be
overloaded?

Cheers,

Luciano


#11

Luciano R. wrote:

I was just wondering whether there is a way, via introspection, to
fetch that list programmatically from Ruby, short of inspecting the
source code for the interpreter.

More or less.

h = []
ObjectSpace.each_object(Class){|c|
h |= c.public_instance_methods.select{|m| m =~ /^\W/}
h |= c.private_instance_methods.select{|m| m =~ /^\W/}
}
ObjectSpace.each_object(Module){|c|
h |= c.public_instance_methods.select{|m| m =~ /^\W/}
h |= c.private_instance_methods.select{|m| m =~ /^\W/}
}
p h

There’s probably some clever way to compute precedence too.

T.


#12

“operators” are only special in that the parser is built to recognize a few
constructs, mainly the mathematical operators (+, -, /, *, etc). For the
programmer’s case, they are all methods on some object, and all methods can
be overwritten. […]

Thanks for the reply, Jason. I realise +, * etc. are method names, but
as Julien just discovered, not all character sequences may be used as
method names.

There is a table in the Pickaxe book [1][2] which lists all Ruby
operators, noting which of them are defined as methods and thus can be
overridden.

I was just wondering whether there is a way, via introspection, to
fetch that list programmatically from Ruby, short of inspecting the
source code for the interpreter.

Cheers,

Luciano

[1] page 339 in 2nd ed
[2] http://www.rubycentral.com/book/html/language.html


#13

Luciano R. wrote:

More or less.
p h

There’s probably some clever way to compute precedence too.

+@ and -@ are prefix operators, so you may not want those. And [] and
[]= are a special in theie own way as well. So that’s the possible
“more”. As for “less”, there may be an operator or two that is legal
but is not defined anywhere in the core set of classes/modules --though
unlikely, I did not check to make sure all where accounted.

T.


#14

On Fri, Dec 22, 2006 at 03:49:30AM +0900, Trans wrote:

Julien G. wrote:

I found it ok compared to ===. But if the interpreter can’t read it…

That one’s ugly too – a word alias for it is in my bag of wishes.

I’d say “casecmp” but that one’s already taken :wink:


#15

Thanks, T. That was awesome!

By why did you say “more or less”? Do you think your code could be
missing something?

Cheers,

Luciano