Arrow operator with dash instead of equals (->)

A

Andrew Green

Hi, all,

Is it possible to use -> as a method name in Ruby?

This code:

class A
def ->(arg)
puts arg
end
end

foo = A.new
foo -> "dummy_argument"

Produces:

~/test2.rb:2: syntax error, unexpected '>', expecting '\n' or
';'
def ->(arg)
^
~/test2.rb:5: syntax error, unexpected kEND, expecting $end

But if I substitute the '->' with '>>', the program works and I get:

dummy_argument

Any idea what's going on here?

Running ruby 1.8.6 on Debian unstable.

Many thanks in advance, greetings,
Andrew Green
 
T

Timothy Hunter

Andrew said:
Hi, all,

Is it possible to use -> as a method name in Ruby?
No. A subset of Ruby's operators are implemented as methods. '>>' is one
of those operators. '->' isn't a Ruby operator at all.

The operators that are implemented as methods are: [], []=, **, !, ~, +,
-, *, /, %, <<, >>,& ^, |, <=>, <=, <, >, >=, ==, ===, and =~.
 
A

Andrew Green

Is it possible to use -> as a method name in Ruby?
No. A subset of Ruby's operators are implemented as methods. '>>' is one
of those operators. '->' isn't a Ruby operator at all.

The operators that are implemented as methods are: [], []=, **, !, ~, +,
-, *, /, %, <<, >>,& ^, |, <=>, <=, <, >, >=, ==, ===, and =~.

So is there no way to make '->' an operator and define its behavior?

If not, what about '=>'?
 
T

Timothy Hunter

Andrew said:
Is it possible to use -> as a method name in Ruby?
No. A subset of Ruby's operators are implemented as methods. '>>' is one
of those operators. '->' isn't a Ruby operator at all.

The operators that are implemented as methods are: [], []=, **, !, ~, +,
-, *, /, %, <<, >>,& ^, |, <=>, <=, <, >, >=, ==, ===, and =~.

So is there no way to make '->' an operator and define its behavior?

If not, what about '=>'?
I listed the Ruby operators that are implemented as methods. '=>' isn't
in the list, is it?

Now, for completeness' sake, it actually is possible to define a method
named '->', but the only way you could call it would be by using 'send',
and I'm guessing you don't want to do that. It would look like this:

o.send('->', args)
 
G

Gary Wright

No. A subset of Ruby's operators are implemented as methods. '>>'
is one of those operators. '->' isn't a Ruby operator at all.

The operators that are implemented as methods are: [], []=, **, !,
~, +, -, *, /, %, <<, >>,& ^, |, <=>, <=, <, >, >=, ==, ===, and =~.

! is not a re-definable operator.



Gary Wright
 
B

Brian Candler

Now, for completeness' sake, it actually is possible to define a method
named '->', but the only way you could call it would be by using 'send',
and I'm guessing you don't want to do that. It would look like this:

o.send('->', args)

This can lead to smiley programming. I recently found myself writing

o.send:)[]=, *args)

It's shorter than

o[args[0..-2]] = args[-1]
 
C

Caleb Clausen

It's not possible to define a -> operator in Ruby, but you can
(sometimes) define <-. Watch:

class Right
def -@
return Negated.new(self)
end

class Negated
def initialize(right)
@inner=right
end

attr :inner
end
end

class Left
def <(negated_right)
self.inspect + " <- " + negated_right.inner.inspect
end
end

Left.new <- Right.new #=> "#<Left:0x403cf68c> <- #<Right:0x403cf678>"

It's actually two operators, so there's a caveat: if the right-side
class already defines unary minus, this won't work.

(I first read about this trick in a C++ book. I'm not necessarily
recommending it.)
 
J

Joel VanderWerf

Brian said:
Now, for completeness' sake, it actually is possible to define a method
named '->', but the only way you could call it would be by using 'send',
and I'm guessing you don't want to do that. It would look like this:

o.send('->', args)

This can lead to smiley programming. I recently found myself writing

o.send:)[]=, *args)

It's shorter than

o[args[0..-2]] = args[-1]

:-D very nice!
 
A

Andrew Green

El lun, 23-04-2007 a las 09:52 +0900, Gary Wright escribió:
No. Ruby does not support user defined operators.


No, '=>' is not an operator in Ruby.

Many thanks for your replies, everyone...

I'll explain briefly why I'm asking:

We're working on a domain-specific language that is mainly declarative
but that includes little snippets of executable code. These snippets
are, at least in our first implementation, in Ruby.

In some of the non-executable parts of the language we declare rules for
traversing segments of a graph using an arror (->). For example:

author -> place_of_birth

or

sibbling -> children -> age

It would be really, really nice to be able to use this same syntax in
the executable Ruby snippets, more or less along the lines of:

(x -> last_names).to_s + ", " + (x -> first_names).to_s

Using a dot instead of an arrow here is not an option for various
reasons.

Any ideas as to how to hack around this limitation in Ruby, then?

Our interpreter eventually gets the code blocks as strings, so I could
just substitute the -> for >> behind the user's back, but that would be
messy, because it would substitute all occurrences of ->, even if
they're in quotes or interpretable by Ruby in some other, unforseen way.
Or is there some clean way of doing this? With ri or something similar,
maybe?

Thanks again,
Andrew

----------

(For anyone curious about what we're doing here, here are some links (in
Spanish):
http://200.67.231.185/mediawiki/index.php/Pescador:Recursos_para_desarrolladores
http://durito.nongnu.org/
)
 
B

Brian Candler

(x -> last_names).to_s + ", " + (x -> first_names).to_s

Using a dot instead of an arrow here is not an option for various
reasons.

Any ideas as to how to hack around this limitation in Ruby, then?

As you say, you could use >>, although it has a fairly low operator
precedence, so

x >> last_names + x >> first_names

would be parsed, I think, as

x >> (last_names + x) >> first_names

If you're going to run through a preprocessor to substitute ->, then "." may
be a better substitution.
Our interpreter eventually gets the code blocks as strings, so I could
just substitute the -> for >> behind the user's back, but that would be
messy, because it would substitute all occurrences of ->, even if
they're in quotes or interpretable by Ruby in some other, unforseen way.
Or is there some clean way of doing this? With ri or something similar,
maybe?

The cleanest way I suspect would be to define a grammar for your own
language, and write a parser for it. I believe there's a Ruby parser
generator out there.

Then you are not bound by the rules of Ruby syntax at all.

Regards,

Brian.
 
A

Andrew Green

El mar, 24-04-2007 a las 04:31 +0900, Brian Candler escribió:
The cleanest way I suspect would be to define a grammar for your own
language, and write a parser for it. I believe there's a Ruby parser
generator out there.

Then you are not bound by the rules of Ruby syntax at all.

Perhaps I didn't explain myself clearly... We _do_ have our own parser
and grammar. The thing is that _within_ our language there are "blocks"
of code that are meant to be processed by the Ruby interpreter. At the
risk of being acused of going off topic, let me offer a little example:

<RuleSet person>
<Structure>
<Descriptor has_given_names>
property swv:hasGivenNames
minCardinality 1
maxCardinality 1
outRequirement fromPropRange
</Descriptor>
<Descriptor has_last_names>
property swv:hasLastNames
minCardinality 1
maxCardinality 1
outRequirement fromPropRange
</Descriptor>
<Descriptor has_parent>
property swv:hasParent
minCardinality 2
maxCardinality 2
outRequirement fromPropRange
</Descriptor>
</Structure>

<KRRelationRules>
<KRRelationRule parent_place_of_birth>
has_parent->place_of_birth
</KRRelationRule>
</KRRelationRules>

<BPVFunctions>
<TextBPVFunction full_name_fl>
orderUsing has_last_names
|{ (ROOT->has_given_names).textBPV + " " + (ROOT->has_last_names).textBPV }|
</TextBPVFunction>
</BPVFunctions>

<Descriptions>
defaultOrderBy has_last_names
VariableDesc default
ShortDesc default
FullDesc default
</Descriptions>
</RuleSet>

(I know, it's very ugly... In the next version we'll replace all the
xml-ish tags with angle brackets and make it all much more succinct.)

Anyway, all of this is processed by our own interpreter, including, for
example, the rule

has_parent->place_of_birth

As you can see it's mainly declarative. However this part

|{ (ROOT->has_given_names).textBPV + " " + (ROOT->has_last_names).textBPV }|

is read by our interpreter only as a string between a |{ and a }| .

That string is then passed to the Ruby interpreter and is meant to be
run (from within a specific context that our interpreter determines). In
these bits we don't want just our language running about, of course, we
want full-blown Ruby code with extensions that allow a programmer to
refer to the graph traversal rules using a syntax similar to that used
in the rule definitions that appear _outside_ the Ruby code blocks.

Thanks again for your advice and apologies if this is considered
off-topic.
 
A

Andrew Green

El mar, 24-04-2007 a las 06:52 +0900, Andrew Green escribió:
(I know, it's very ugly... In the next version we'll replace all the
xml-ish tags with angle brackets and make it all much more succinct.)

(Did I say angle brackets...? I meant curlies... I guess now I'm
_really_ off-topic... sorry.)
 
B

Brian Candler

Anyway, all of this is processed by our own interpreter, including, for
example, the rule

has_parent->place_of_birth

As you can see it's mainly declarative. However this part

|{ (ROOT->has_given_names).textBPV + " " + (ROOT->has_last_names).textBPV }|

is read by our interpreter only as a string between a |{ and a }| .

That string is then passed to the Ruby interpreter and is meant to be
run (from within a specific context that our interpreter determines). In
these bits we don't want just our language running about, of course, we
want full-blown Ruby code with extensions that allow a programmer to
refer to the graph traversal rules using a syntax similar to that used
in the rule definitions that appear _outside_ the Ruby code blocks.

And my suggestion still stands: if what you want to appear inside {..} is a
language which has -> as an operator, then a 'clean' (albeit heavyweight)
option is to write your own expression parser using an LALR parser
generator.

The expression parser can build a syntax tree, and then you can either walk
this tree yourself, or use it to generate Ruby code as its output, which you
can then run.

A completely different option would be to use Perl instead of Ruby, since
Perl has a -> dereference operator. But then you will have to put lots of
dollar signs and curly brackets in.

B.
 
M

Martin DeMello

As you can see it's mainly declarative. However this part

|{ (ROOT->has_given_names).textBPV + " " + (ROOT->has_last_names).textBPV }|

is read by our interpreter only as a string between a |{ and a }| .

That string is then passed to the Ruby interpreter and is meant to be
run (from within a specific context that our interpreter determines). In
these bits we don't want just our language running about, of course, we
want full-blown Ruby code with extensions that allow a programmer to
refer to the graph traversal rules using a syntax similar to that used
in the rule definitions that appear _outside_ the Ruby code blocks.

Rather than leaving the |{}| blocks entirely alone, you could
preprocess them to change the -> to something ruby will accept, and
then run the interpreter over the preprocessed string. Won't be a
trivial task, but should be easier than any of the alternatives.

martin
 
A

Andrew Green

El mié, 25-04-2007 a las 00:04 +0900, Martin DeMello escribió:
Rather than leaving the |{}| blocks entirely alone, you could
preprocess them to change the -> to something ruby will accept, and
then run the interpreter over the preprocessed string. Won't be a
trivial task, but should be easier than any of the alternatives.


El mar, 24-04-2007 a las 17:48 +0900, Brian Candler escribió:
And my suggestion still stands: if what you want to appear inside {..} is a
language which has -> as an operator, then a 'clean' (albeit heavyweight)
option is to write your own expression parser using an LALR parser
generator.

The expression parser can build a syntax tree, and then you can either walk
this tree yourself, or use it to generate Ruby code as its output, which you
can then run.

OK. Everything seems to indicate this is the way to go, in the
long-to-medium term. Thanks, Brian, Martin and everyone else, for all
your help.

Andrew
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top