[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Syntax error when redefining >> operator to take a block

John Woods

10/12/2007 5:39:00 AM

I'm trying to redefine the >> operator for a particular class such that
it takes a block as its argument. It works if I invoke the redifined >>
operator using "." syntax, but causes a syntax error otherwise.

This code illustrates my problem:

class C
def >>(&block)
block.call("inside >>")
end
end

c = C.new
c.>> { |x| puts x } # outputs "inside >>"
#c >> { |x| puts x } # syntax error, if uncommented

This is the syntax error reported:

test.rb:10: syntax error, unexpected '|', expecting '}'
c >> { |x| puts x } # syntax error, if uncommented
^
test.rb:10: syntax error, unexpected tIDENTIFIER, expecting kDO or '{'
or '('
c >> { |x| puts x } # syntax error, if uncommented
^

Any pointers? Thanks.


8 Answers

Robert Klemme

10/12/2007 12:04:00 PM

0

2007/10/12, John Woods <jqwoods@gmail.com>:
> I'm trying to redefine the >> operator for a particular class such that
> it takes a block as its argument. It works if I invoke the redifined >>
> operator using "." syntax, but causes a syntax error otherwise.
>
> This code illustrates my problem:
>
> class C
> def >>(&block)
> block.call("inside >>")
> end
> end
>
> c = C.new
> c.>> { |x| puts x } # outputs "inside >>"
> #c >> { |x| puts x } # syntax error, if uncommented
>
> This is the syntax error reported:
>
> test.rb:10: syntax error, unexpected '|', expecting '}'
> c >> { |x| puts x } # syntax error, if uncommented
> ^
> test.rb:10: syntax error, unexpected tIDENTIFIER, expecting kDO or '{'
> or '('
> c >> { |x| puts x } # syntax error, if uncommented
> ^
>
> Any pointers? Thanks.

Redefining operator behavior cannot change Ruby's syntax. >> is with
a block is just not valid Ruby syntax - as you have seen.

robert

John Woods

10/12/2007 6:22:00 PM

0

>> I'm trying to redefine the >> operator for a particular class such that
>> it takes a block as its argument. It works if I invoke the redifined >>
>> operator using "." syntax, but causes a syntax error otherwise.
>>
>> [...snip...]
>>
>> Any pointers? Thanks.
>
> Redefining operator behavior cannot change Ruby's syntax. >> is with
> a block is just not valid Ruby syntax - as you have seen.

I don't understand why it's invalid syntax. I'm new to Ruby and am
looking to better understand.

Please consider these two different definitions of >>

def >>(arg) ....
def >>(&arg) ....

and these two different invocations of >>

c >> { }
c.>> { }

In the following example, the first invocation works with the first
definition, and the second with the second. However the first/second
invocation doesn't work second/first definition, respectively.

class C
def >>(arg)
puts arg.class
end
end

c = C.new

c >> { } # outputs 'Hash'
#c.>> { } # syntax error: wrong number of args (0 for 1)

class C
def >>(&arg)
puts arg.class
end
end

c.>> { } # outputs 'Proc'
#c >> { } # syntax error: wrong number of args (1 for 0)

It seems that if the operator is invoked with only optional whitespace
between the receiver "c" and the operator ">>" then ruby interprets the
following { ... } to be a hash, and if the operator is invoked with a
"." then ruby interprets { ... } to be a proc. And this appears to be
regardless of what's actually between the braces, or regardless of how
the argument to >> is defined (ie with or without the "&").

I'm wondering why ruby doesn't instead interpret { ... } to be either a
hash or a proc based on what's inside the braces. For example, { 1 =>
"one" } is a hash, and { |x| x + x } is a proc. It seems to me this
distinction should be made by what's between the braces, and not whether
there's a " " or "." between the receiver and the operator. Then, if
there's a mismatch between what's being passed and the operator
definition, I would expect an error.

So is this an area where Ruby's parsing could be improved to enable
passing a block to an operator (without having to use "." to invoke the
operator)? Or, am I misunderstanding something? Any insight would be
appreciated.


Robert Klemme

10/12/2007 10:37:00 PM

0

On 12.10.2007 20:22, John Woods wrote:
>>> I'm trying to redefine the >> operator for a particular class such that
>>> it takes a block as its argument. It works if I invoke the redifined >>
>>> operator using "." syntax, but causes a syntax error otherwise.
>>>
> >> [...snip...]
>>>
>>> Any pointers? Thanks.
>>
>> Redefining operator behavior cannot change Ruby's syntax. >> is with
>> a block is just not valid Ruby syntax - as you have seen.
>
> I don't understand why it's invalid syntax. I'm new to Ruby and am
> looking to better understand.
>
> Please consider these two different definitions of >>
>
> def >>(arg) ....
> def >>(&arg) ....
>
> and these two different invocations of >>
>
> c >> { }
> c.>> { }
>
> In the following example, the first invocation works with the first
> definition, and the second with the second. However the first/second
> invocation doesn't work second/first definition, respectively.
>
> class C
> def >>(arg)
> puts arg.class
> end
> end
>
> c = C.new
>
> c >> { } # outputs 'Hash'
> #c.>> { } # syntax error: wrong number of args (0 for 1)
>
> class C
> def >>(&arg)
> puts arg.class
> end
> end
>
> c.>> { } # outputs 'Proc'
> #c >> { } # syntax error: wrong number of args (1 for 0)
>
> It seems that if the operator is invoked with only optional whitespace
> between the receiver "c" and the operator ">>" then ruby interprets the
> following { ... } to be a hash, and if the operator is invoked with a
> "." then ruby interprets { ... } to be a proc. And this appears to be
> regardless of what's actually between the braces, or regardless of how
> the argument to >> is defined (ie with or without the "&").

I cannot be different because - as I have said before - a method /
operator (re-)definition cannot change the syntax of the language. For
syntax it is completely irrelevant how you define a method / operator.

Here are some examples:

robert@fussel ~
$ ruby -e 'def self.>>(*a,&b) p a,b end; self.>> {}'
[]
#<Proc:0x00000000@-e:1>

robert@fussel ~
$ ruby -e 'def self.>>(*a,&b) p a,b end; self.>>({})'
[{}]
nil

robert@fussel ~
$ ruby -e 'def self.>>(*a,&b) p a,b end; self.>>(){}'
[]
#<Proc:0x00000000@-e:1>

robert@fussel ~
$ ruby -e 'def self.>>(*a,&b) p a,b end; self >> {}'
[{}]
nil

robert@fussel ~
$ ruby -e 'def self.>>(*a,&b) p a,b end; self.>> {|x|}'
[]
#<Proc:0x00000000@-e:1>

robert@fussel ~
$ ruby -e 'def self.>>(*a,&b) p a,b end; self.>>() {|x|}'
[]
#<Proc:0x00000000@-e:1>

robert@fussel ~
$ ruby -e 'def self.>>(*a,&b) p a,b end; self >> {|x|}'
-e:1: syntax error, unexpected '|', expecting '}'
def self.>>(*a,&b) p a,b end; self >> {|x|}
^
When you use the dot notation then the expression is a normal method
invocation just with an unusual method name. So all the normal method
invocation syntax applies and in that case {} is interpreted as block -
no matter what.

When you use the operator syntax (i.e. no dot) Ruby tries to parse the
right hand side as an expression, which could only be a Hash in this
case since a block is not an expression. You need an expression on the
right hand side because >> is a binary operator.

> I'm wondering why ruby doesn't instead interpret { ... } to be either a
> hash or a proc based on what's inside the braces. For example, { 1 =>
> "one" } is a hash, and { |x| x + x } is a proc. It seems to me this
> distinction should be made by what's between the braces, and not whether
> there's a " " or "." between the receiver and the operator. Then, if
> there's a mismatch between what's being passed and the operator
> definition, I would expect an error.

And what is {}? It's both a valid Hash and block. And actually Ruby
does parse accordingly:

robert@fussel ~
$ ruby -ce 'a >> do |x| end'
-e:1: syntax error, unexpected kDO
a >> do |x| end
^

robert@fussel ~
$ ruby -ce 'a >> {|x| }'
-e:1: syntax error, unexpected '|', expecting '}'
a >> {|x| }
^

robert@fussel ~
$ ruby -ce 'a >> {}'
Syntax OK


> So is this an area where Ruby's parsing could be improved to enable
> passing a block to an operator (without having to use "." to invoke the
> operator)? Or, am I misunderstanding something? Any insight would be
> appreciated.

I would not consider it an improvement since I don't see a point in
passing a block to an operator. I don't see need for improvement here.

Kind regards

robert

John Joyce

10/12/2007 11:08:00 PM

0

Generally, you don't need to try and create or override operators in
Ruby.
It's just not worth the trouble.
It's a lot easier (probably intentionally) to just create a normal
method or function.
It's not C++
Try to make it readable by humans.

Arlen Cuss

10/13/2007 2:51:00 AM

0

Hi,

On Fri, 2007-10-12 at 14:39 +0900, John Woods wrote:
> I'm trying to redefine the >> operator for a particular class such that
> it takes a block as its argument. It works if I invoke the redifined >>
> operator using "." syntax, but causes a syntax error otherwise.

I think the problem is summed up shortly in another reply, but --

>> is a binary operator, meaning it must accept one argument. Block
arguments are treated in a special manner (e.g. the arity of a method
which takes only a block is 0), and thus aren't valid as the other
operand of a binary operator!

HTH your understanding a bit,
arlen


John Woods

10/13/2007 5:10:00 PM

0

Thanks guys, I now understand much better what's going on with my
attempt to redefine >>. This list is great!


Rick DeNatale

10/13/2007 5:43:00 PM

0

On 10/12/07, Arlen Christian Mart Cuss <celtic@sairyx.org> wrote:
> Hi,
>
> On Fri, 2007-10-12 at 14:39 +0900, John Woods wrote:
> > I'm trying to redefine the >> operator for a particular class such that
> > it takes a block as its argument. It works if I invoke the redifined >>
> > operator using "." syntax, but causes a syntax error otherwise.
>
> I think the problem is summed up shortly in another reply, but --
>
> >> is a binary operator, meaning it must accept one argument. Block
> arguments are treated in a special manner (e.g. the arity of a method
> which takes only a block is 0), and thus aren't valid as the other
> operand of a binary operator!

Note from the post which started this thread:

c.>> { |x| puts x } # outputs "inside >>"
#c >> { |x| puts x } # syntax error, if uncommented

It really doesn't have to do with the arity of the method. It's the
way the statement is parsed, the parser doesn't check arity, in fact I
don't think it could if it wanted to, it doesn't know what method
would be bound to :>> for an arbitrary value of c.

That '.' on the first line makes all the difference, The c >> x is
syntactic sugar for sure which the parser turns into what gets
evaluated effectively as c.>>(x) but since the parser doesn't see a
valid x it results in a syntax error.



--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

Robert Klemme

10/13/2007 6:10:00 PM

0

On 13.10.2007 19:43, Rick DeNatale wrote:
> On 10/12/07, Arlen Christian Mart Cuss <celtic@sairyx.org> wrote:
>> Hi,
>>
>> On Fri, 2007-10-12 at 14:39 +0900, John Woods wrote:
>>> I'm trying to redefine the >> operator for a particular class such that
>>> it takes a block as its argument. It works if I invoke the redifined >>
>>> operator using "." syntax, but causes a syntax error otherwise.
>> I think the problem is summed up shortly in another reply, but --
>>
>>>> is a binary operator, meaning it must accept one argument. Block
>> arguments are treated in a special manner (e.g. the arity of a method
>> which takes only a block is 0), and thus aren't valid as the other
>> operand of a binary operator!
>
> Note from the post which started this thread:
>
> c.>> { |x| puts x } # outputs "inside >>"
> #c >> { |x| puts x } # syntax error, if uncommented
>
> It really doesn't have to do with the arity of the method. It's the
> way the statement is parsed, the parser doesn't check arity, in fact I
> don't think it could if it wanted to, it doesn't know what method
> would be bound to :>> for an arbitrary value of c.
>
> That '.' on the first line makes all the difference, The c >> x is
> syntactic sugar for sure which the parser turns into what gets
> evaluated effectively as c.>>(x) but since the parser doesn't see a
> valid x it results in a syntax error.

Yeah, and that's why operators are special in a way when it comes to
arity. Although you can define them with arbitrary arity the normal
usage of a binary operator enforces exactly one argument (plus self of
course) and thus practically enforces arity one - even if you can pass
more arguments when using dot notation.


irb(main):001:0> def +(*a)p a end
=> nil
irb(main):002:0> self.+ 1,2,3
[1, 2, 3]
=> nil
irb(main):003:0> self + 1
[1]
=> nil

Kind regards

robert