Syntax error when redefining >> operator to take a block

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.

2007/10/12, John W. [email protected]:

end
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

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.

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.

On 12.10.2007 20:22, John W. wrote:

c >> { }
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

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

Hi,

On Fri, 2007-10-12 at 14:39 +0900, John W. 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

On 10/12/07, Arlen Christian Mart C. [email protected] wrote:

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.denhaven2.com/

On 13.10.2007 19:43, Rick DeNatale wrote:

arguments are treated in a special manner (e.g. the arity of a method
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