[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Method named ***(other

Julien Gaugaz

12/21/2006 4:08:00 PM

Hi!

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

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:in `each'
from (irb):23:in `collect2'
from (irb):22:in `each'
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 ;-) )

Thanks a lot in advance for your help and advices!

Julien


13 Answers

Vidar Hokstad

12/21/2006 4:30:00 PM

0


Julien Gaugaz wrote:
> Hi!
>
> It's several hours now that i'm trying to find out what's special with
> *** for a method name, without success :(

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

Julien Gaugaz

12/21/2006 4:46:00 PM

0

>
> Julien Gaugaz wrote:
>> Hi!
>>
>> It's several hours now that i'm trying to find out what's special with
>> *** for a method name, without success :(
>
> 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.
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
>
> Vidar
>
>
>

Wilson Bilkovich

12/21/2006 4:51:00 PM

0

On 12/21/06, Julien Gaugaz <gaugaz@l3s.de> wrote:
> >
> > Julien Gaugaz wrote:
> >> Hi!
> >>
> >> It's several hours now that i'm trying to find out what's special with
> >> *** for a method name, without success :(
> >
> > 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.
> 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. :)

Julien Gaugaz

12/21/2006 5:05:00 PM

0

> On 12/21/06, Julien Gaugaz <gaugaz@l3s.de> wrote:
>> >
>> > Julien Gaugaz wrote:
>> >> Hi!
>> >>
>> >> It's several hours now that i'm trying to find out what's special
>> with
>> >> *** for a method name, without success :(
>> >
>> > 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.
>> 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.
Ah ok! I get it!!!! :-D Thanks a lot!
> Also, *** is unreadably nasty, so it's good that you can't name a
> method that. :)
:-)
I found it ok compared to ===. But if the interpreter can't read it...
>
>

Vidar Hokstad

12/21/2006 5:08:00 PM

0


Julien Gaugaz 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

Julien Gaugaz

12/21/2006 5:28:00 PM

0

Vidar Hokstad wrote:
> Julien Gaugaz 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#**.
>
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 ;-)

Thank you again for those enlightenments!

Cheers,

Julien
> Vidar
>
>
> Vidar
>
>
>
>

Trans

12/21/2006 6:50:00 PM

0


Julien Gaugaz 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.


ramalho@gmail.com

12/21/2006 7:00:00 PM

0

On 12/21/06, Vidar Hokstad <vidar.hokstad@gmail.com> 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

ramalho@gmail.com

12/21/2006 7:37:00 PM

0

> "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/lan...

Trans

12/21/2006 10:04:00 PM

0


Luciano Ramalho 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.