Are we cool? method_missing in enumerator

T

Trans

Can anyone demonstrate problems with the following?

# Adds immediate elementwise ability to Enumerator.
# Any non-enumeration method is passed on to each.
#
# [1,2,3].to_enum:)map) + 3
# => [4,5,6]
#
# Note there may be a few essential methods this can not
# be used on, such as #object_id.

class Enumerable::Enumerator
def method_missing(sym,*args,&blk)
each{ |x| x.send(sym,*args,&blk) }
end
end

I like the simplicity of this and would rather use it than add an
another class layer, but I need to be sure I'm not overlooking any
potential dangers with doing so.

Thanks,
T.
 
R

Robert Klemme

2007/7/17 said:
Can anyone demonstrate problems with the following?

# Adds immediate elementwise ability to Enumerator.
# Any non-enumeration method is passed on to each.
#
# [1,2,3].to_enum:)map) + 3
# => [4,5,6]
#
# Note there may be a few essential methods this can not
# be used on, such as #object_id.

class Enumerable::Enumerator
def method_missing(sym,*args,&blk)
each{ |x| x.send(sym,*args,&blk) }
end
end

I like the simplicity of this and would rather use it than add an
another class layer, but I need to be sure I'm not overlooking any
potential dangers with doing so.

Cool indeed! The only thing that comes to mind at the moment is a
certain inconsistency that this creates: all methods implemented in
the Enumerator are methods operating on the collection while methods
invoked by your extension are invoked per instance in the collection.
I am not sure whether that actually disqualifies the change as a std
lib change...

Btw, your sample would be equally simple by doing [1,2,3].map {|x|
x+3} - it's even less typing. ;-)

Kind regards

robert
 
R

Robert Dober

Can anyone demonstrate problems with the following?

# Adds immediate elementwise ability to Enumerator.
# Any non-enumeration method is passed on to each.
#
# [1,2,3].to_enum:)map) + 3
# => [4,5,6]
#
# Note there may be a few essential methods this can not
# be used on, such as #object_id.

class Enumerable::Enumerator
def method_missing(sym,*args,&blk)
each{ |x| x.send(sym,*args,&blk) }
end
end

I like the simplicity of this and would rather use it than add an
another class layer, but I need to be sure I'm not overlooking any
potential dangers with doing so.
Hmm I do it like this in Labrador, but on map directly and I add a
class overlay so that indeed things like #object_id can be dispatched

irb(main):002:0> require 'labrador/enum'
=> true
irb(main):003:0> [1,2,3].map.object_id
=> [3, 5, 7]
irb(main):004:0>

I would indeed be very interested in dangers of this, but my
announcement went unnoticed, quite normal given the undocumented and
unstructured state of Labrador -- I work less than 1h/w for it :(.

I really do not like -- or know -- this to_enum stuff, it seems way to
verbose for me.
Attention I am not going to influence the community I just want to
find some fellow soul who likes my style. (Notably Magic Dot)

Sorry if I am hijacking a little bit, just say a word and I'll go away...

Robert
 
R

Robert Dober

Btw, your sample would be equally simple by doing [1,2,3].map {|x|
x+3} - it's even less typing. ;-)
I offer
irb(main):001:0> require 'labrador/enum'
=> true
irb(main):002:0> (1..3).map + 3
=> [4, 5, 6]
irb(main):003:0> (1..3).map:)+, 3)
=> [4, 5, 6]
Kind regards

robert
Robert
 
S

Sammy Larbi

I might test that it can still throw missing method exception if the
called method isn't supposed to be doing what you're making it do (ie,
perhaps it was a typo)

Sam


Trans wrote, On 7/17/2007 9:01 AM:
 
T

Trans

Btw, your sample would be equally simple by doing [1,2,3].map {|x|
x+3} - it's even less typing. ;-)

I offer
irb(main):001:0> require 'labrador/enum'
=> true
irb(main):002:0> (1..3).map + 3
=> [4, 5, 6]
irb(main):003:0> (1..3).map:)+, 3)
=> [4, 5, 6]

Yep. This works with my implementation too as of Ruby 1.9+ because the
enumerable methods will return an enumerator if no block is given.

T.
 
T

Trans

I might test that it can still throw missing method exception if the
called method isn't supposed to be doing what you're making it do (ie,
perhaps it was a typo)

Sam

Trans wrote, On 7/17/2007 9:01 AM:
Can anyone demonstrate problems with the following?
# Adds immediate elementwise ability to Enumerator.
# Any non-enumeration method is passed on to each.
#
# [1,2,3].to_enum:)map) + 3
# => [4,5,6]
#
# Note there may be a few essential methods this can not
# be used on, such as #object_id.
class Enumerable::Enumerator
def method_missing(sym,*args,&blk)
each{ |x| x.send(sym,*args,&blk) }
end
end
I like the simplicity of this and would rather use it than add an
another class layer, but I need to be sure I'm not overlooking any
potential dangers with doing so.

Yea, that's the "danger" part, because it's going to try to apply that
typo to the enumerable's elements. I many cases that will no doubt
fail --in which case maybe it wouldn't hurt to but it in a begin
rescue clause in order to give a more comprehensible error message.
OTOH, some typos might get through, in which case testing is key.

I think I've come up with a good alternative that is safer, but still
reads well (as of 1.9):

arr.map.x + 3

What do you think?

T.
 
R

Robert Dober

This being true, where exactly is the difference between

enum.map{ |e| e.typo }
and
enum.map:)typo)

<snip>
Robert
 
D

Daniel DeLorme

Trans said:
I think I've come up with a good alternative that is safer, but still
reads well (as of 1.9):

arr.map.x + 3

What do you think?

I'll throw out this idea from a thread not so long ago:

arr.map.it + 3

;)
Daniel
 
R

Robert Klemme

2007/7/19 said:
Hi --



I'm afraid there's too much "invisible ink" there for me.

That's a great way to put it! With your (other) own words, I think
this is unbalanced. Too much coolness, to few readability.

Kind regards

robert
 
T

Trans

Hi --





I'm afraid there's too much "invisible ink" there for me.

Well, what does that mean? Clearly you find it uncomfortable in some
manner. Is it just the magic-dot again? Or something else? Is the
original

arr.map + 3

okay? Or are both too much "invisible ink". What is wrong with it/them
more concretely?

Thanks,
T.
 
S

Sammy Larbi

Robert Dober wrote, On 7/18/2007 3:48 PM:
This being true, where exactly is the difference between

enum.map{ |e| e.typo }
and
enum.map:)typo)

<snip>
Robert

Good point. I guess I was thinking of something unrelated to the map
call: Where you've got the magic behavior working fine, but somewhere
later on you have a method typo, but that gets caught by method_missing
and throws some different strange error instead of method missing.

Sam
 
R

Robert Dober

At a glance, I can't tell if arr is a object with an attribute named map
that you're adding 3 to (and never storing). Does this return a value, or
does it modify in place? If it returns a value, then you'd end up with a
statement like

new_arr = arr.map + 3

without knowing a lot of specifics about arr, map, and this magic, I would
totally assume that map is an attribute of arr, and you're adding 3 to it.

This sort of shortcut is the kind of thing I would use in a DSL where
certain context is assumed, but wouldn't use in day to day programming, it's
just too ambiguous.
This is indeed true, the art might be to find the balance (how is it
going David? ;) between conciseness and readability.
Your DSL example is excellent because it restricts users to a circle
talking the same jargon, more generally I think one has to think about
who will read the code.
Consistency comes in too ( I did not do it on purpose ) if you write
all your code like that a potential new team member or maintainer will
learn your ways quickly...

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

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,586
Members
45,085
Latest member
cryptooseoagencies

Latest Threads

Top