Why can't I redefine "<<" method to allow two parameters?

  • Thread starter Iñaki Baz Castillo
  • Start date
I

Iñaki Baz Castillo

SGksIHZlcnkgZXhydGFuZ2U6CgoKY2xhc3MgTXlBcnJheSA8IEFycmF5CiAgYWxpYXMgb3JpZ2lu
YWxfYWRkIDw8CiAgZGVmIDw8KG4saykKICAgIG9yaWdpbmFsX2FkZCAiI3tufTogI3trfSIKICBl
bmQKZW5kCgpteV9hcnJheSA9IE15QXJyYXkubmV3Cj0+IFtdCgpteV9hcnJheSA8PCAoIkhlYWRl
ciIsICJWYWx1ZSIpCgpTeW50YXhFcnJvcjogY29tcGlsZSBlcnJvcgooaXJiKToyNTogc3ludGF4
IGVycm9yLCB1bmV4cGVjdGVkICcsJywgZXhwZWN0aW5nICcpJwpteV9hcnJheSA8PCAoIkhlYWRl
ciIsICJWYWx1ZSIpCiAgICAgICAgICAgICAgICAgICAgICAgICBeCgoKQW55IHJlYXNvbiBmb3Ig
dGhpcz8gSXQgc2VlbXMgdGhhdCA8PCBpcyBhIGxpdHRsZWQgImhhcmRjb2RlZCIsIGlzbid0PwoK
LS0gCknDsWFraSBCYXogQ2FzdGlsbG8KPGliY0BhbGlheC5uZXQ+Cg==
 
J

Jason Roelofs

Hi, very exrtange:


class MyArray < Array
alias original_add <<
def <<(n,k)
original_add "#{n}: #{k}"
end
end

my_array =3D MyArray.new
=3D> []

my_array << ("Header", "Value")

SyntaxError: compile error
(irb):25: syntax error, unexpected ',', expecting ')'
my_array << ("Header", "Value")
^


Any reason for this? It seems that << is a littled "hardcoded", isn't?

The << operator is a special case handled by the parser, but you can
bypass that handling by calling the method directly:

my_array.<<("Header", "Value")

which will of course look a ton better by just using a custom method:

my_array.add_stuff "Header", "Value"

Jason R.
 
I

Iñaki Baz Castillo

MjAwOC81LzgsIEnDsWFraSBCYXogQ2FzdGlsbG8gPGliY0BhbGlheC5uZXQ+Ogo+ICBBbnkgcmVh
c29uIGZvciB0aGlzPyBJdCBzZWVtcyB0aGF0IDw8IGlzIGEgbGl0dGxlZCAiaGFyZGNvZGVkIiwg
aXNuJ3Q/CgpTb3JyeSwgaXQgd2FzIGEgZmFpbHVyZSBvZiBtaW5lLiBJdCB3b3JrcyBvay4KCi0t
IApJw7Fha2kgQmF6IENhc3RpbGxvCjxpYmNAYWxpYXgubmV0Pgo=
 
R

Rick DeNatale

Hi, very exrtange:


class MyArray < Array
alias original_add <<
def <<(n,k)
original_add "#{n}: #{k}"
end
end

my_array =3D MyArray.new
=3D> []

my_array << ("Header", "Value")

SyntaxError: compile error
(irb):25: syntax error, unexpected ',', expecting ')'
my_array << ("Header", "Value")

The parser sees the << OPERATOR as taking a left and right argument,
and turns that into a message send to the left argument. If you want
to use additional arguments you need to be a bit more explicit and use
a little less syntactic sugar:

my_array.<<("Header","Value") # =3D> ["Header: Value"]

--=20
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/
 
I

Iñaki Baz Castillo

MjAwOC81LzgsIEnDsWFraSBCYXogQ2FzdGlsbG8gPGliY0BhbGlheC5uZXQ+Ogo+IDIwMDgvNS84
LCBJw7Fha2kgQmF6IENhc3RpbGxvIDxpYmNAYWxpYXgubmV0PjoKPgo+ID4gIEFueSByZWFzb24g
Zm9yIHRoaXM/IEl0IHNlZW1zIHRoYXQgPDwgaXMgYSBsaXR0bGVkICJoYXJkY29kZWQiLCBpc24n
dD8KPgo+Cj4gU29ycnksIGl0IHdhcyBhIGZhaWx1cmUgb2YgbWluZS4gSXQgd29ya3Mgb2suCgoK
Tm9vb29vb29vbywgaXQgZG9lc24ndCB3b3JrIE9LIGF0IGFsbCEhIQoKSXQganVzdCB3b3JrcyBp
ZiBJIGNhbGwgdG8gdGhlIHJlZGVmaW5lZCA8PCBtZXRob2Qgd2l0aCBET1QgYW5kCmFyZ3VtZW50
cyBiZXR3ZWVuICggKToKCiAgbXlfYXJyYXkuPDwoImhvbGEiLCJwZXBlIikgICAgICMgTm90ZSB0
aGUgRE9UIGluIC48PAogID0+IFsiaG9sYTogcGVwZSJdCgogIG15X2FycmF5PDwoImhvbGEiLCJw
ZXBlIikgICAgICAjIFdpdGhvdXQgRE9UCiAgU3ludGF4RXJyb3I6IGNvbXBpbGUgZXJyb3IKICAo
aXJiKToxMTogc3ludGF4IGVycm9yLCB1bmV4cGVjdGVkICcsJywgZXhwZWN0aW5nICcpJwogIG15
X2FycmF5PDwoImhvbGEiLCJwZXBlIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBeCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnJvbSAoaXJiKToxMQogICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyb20gOjAKCldoeT8/CgotLSAKScOxYWtp
IEJheiBDYXN0aWxsbwo8aWJjQGFsaWF4Lm5ldD4K
 
J

Jens Wille

Jason Roelofs [2008-05-08 14:50]:
Hi, very exrtange:


class MyArray < Array
alias original_add <<
def <<(n,k)
original_add "#{n}: #{k}"
end
end

my_array = MyArray.new
=> []

my_array << ("Header", "Value")

SyntaxError: compile error
(irb):25: syntax error, unexpected ',', expecting ')'
my_array << ("Header", "Value")
^


Any reason for this? It seems that << is a littled "hardcoded", isn't?

The << operator is a special case handled by the parser, but you can
bypass that handling by calling the method directly:
the point is that you can't call an operator with multiple
arguments. maybe something like this will suit you (note that you
don't need to alias if you inherit from Array):

class MyArray < Array
def <<(*a)
a = [*(a=*a)] # a.to_a.flatten_once ;-)
raise ArgumentError, "wrong number of arguments (#{a.size} for
2)" if a.size != 2

super a.join(': ')
end
end

my_array = MyArray.new
my_array << ['Header1', 'Value1'] # => ["Header1: Value1"]
my_array.<<('Header2', 'Value2') # => ["Header1: Value1",
"Header2: Value2"]

cheers
jens

--
Jens Wille, Dipl.-Bibl. (FH)
prometheus - Das verteilte digitale Bildarchiv für Forschung & Lehre
Kunsthistorisches Institut der Universität zu Köln
Albertus-Magnus-Platz, D-50923 Köln
Tel.: +49 (0)221 470-6668, E-Mail: (e-mail address removed)
http://www.prometheus-bildarchiv.de/
 
R

Robert Klemme

2008/5/8 I=F1aki Baz Castillo said:
2008/5/8 said:
?


Sorry, it was a failure of mine. It works ok.


Nooooooooo, it doesn't work OK at all!!!

It just works if I call to the redefined << method with DOT and
arguments between ( ):

my_array.<<("hola","pepe") # Note the DOT in .<<
=3D> ["hola: pepe"]

my_array<<("hola","pepe") # Without DOT
SyntaxError: compile error
(irb):11: syntax error, unexpected ',', expecting ')'
my_array<<("hola","pepe")
^
from (irb):11
from :0

Why??

As others have pointed out it is not an issue of method #<< but of the
syntax. In other words, the syntax allows for << just one argument to
the left and one to the right (similar to #+ and all other _binary_
operators). While you can define the method #<< to accept any number
of arguments the parser simply won't call it with more than one
argument because that is a syntax error:

15:23:08 $ ruby -ce '1 << 2'
Syntax OK
15:23:11 $ ruby -ce '1 << 2 3'
-e:1: syntax error, unexpected tINTEGER, expecting $end
15:23:14 $ ruby -ce '1 << 2,3'
-e:1: syntax error, unexpected ',', expecting $end
1 << 2,3
^
15:23:16 $

HTH

Kind regards

robert

--=20
use.inject do |as, often| as.you_can - without end
 
J

Jimmy Kofler

Why can't I redefine "<<" method to allow two parameters?
Posted by Iñaki Baz Castillo (Guest) on 08.05.2008 14:42
Hi, very exrtange:
...
my_array << ("Header", "Value")

This seems to work as well:

ruby -e 'p [1,2,3] << 4 << 5'
#=> [1, 2, 3, 4, 5]

Cheers,

j.k.
 
P

Phillip Gawlowski

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

David A. Black wrote:

|> ruby -e 'p [1,2,3] << 4 << 5'
|> #=> [1, 2, 3, 4, 5]
|
| What do you guys have against #push? :)

Nothing that works. ;P

Seriously, though: I prefer it. It makes it explicit what I'm doing.

No confusion possible with, say, a HERE doc (sp?), or a bitshift operator.

- --
Phillip Gawlowski
Twitter: twitter.com/cynicalryan
Blog: http://justarubyist.blogspot.com

~ - You know you've been hacking too long when...
...you almost get hit by a bus that pulled away from the stop without
looking and you say: PANIC: bus error
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkgjIWgACgkQbtAgaoJTgL8LNwCglHoCwu4F0n7zBSfKSQ+HySkm
9KEAnRRD2lzMy500iinYqwi+yPTqWMYj
=TxDg
-----END PGP SIGNATURE-----
 
R

Rick DeNatale

Hi --
Jason Roelofs [2008-05-08 14:50]:


the point is that you can't call an operator with multiple
arguments. maybe something like this will suit you (note that you
don't need to alias if you inherit from Array):

class MyArray < Array
def <<(*a)
a =3D [*(a=3D*a)] # a.to_a.flatten_once ;-)
raise ArgumentError, "wrong number of arguments (#{a.size} for
2)" if a.size !=3D 2

super a.join(': ')

end
end

my_array =3D MyArray.new

my_array << ['Header1', 'Value1'] # =3D> ["Header1: Value1"]
my_array.<<('Header2', 'Value2') # =3D> ["Header1: Value1",
"Header2: Value2"]


Thanks to all. Finally I'll just create a "add" method that will call
internally to << method using appropiate syntax:
self.<< (k, v)

I would just use Array#push:

=3D> [1, 2, 3, 4, 5]

We seem to have lost track of what the OP was trying to do,

class MyArray < Array
alias original_add <<
def <<(n,k)
original_add "#{n}: #{k}"
end
end

He wants

[1,2,3].whatever_the_heck_he_decides_to_call_it(4,5) #=3D> [1,2,3, "4:5"]


--=20
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/
 
R

Robert Klemme

2008/5/8 Rick DeNatale said:
We seem to have lost track of what the OP was trying to do,

class MyArray < Array
alias original_add <<
def <<(n,k)
original_add "#{n}: #{k}"
end
end

He wants

[1,2,3].whatever_the_heck_he_decides_to_call_it(4,5) #=> [1,2,3, "4:5"]

There is always the option to work with an intermediary:

irb(main):001:0> class MyArray < Array
irb(main):002:1> ArrayAppender = Struct.new :array, :name do
irb(main):003:2* def <<(value)
irb(main):004:3> array.push "#{name}: #{value}"
irb(main):005:3> end
irb(main):006:2> end
irb(main):007:1> def <<(name)
irb(main):008:2> ArrayAppender.new self, name
irb(main):009:2> end
irb(main):010:1> end
=> nil
irb(main):011:0> a = MyArray.new
=> []
irb(main):012:0> a << 4 << 5
=> ["4: 5"]
irb(main):013:0>

Kind regards

robert
 

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

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top