Object#each?

A weird idea just popped into my head:

class Object
def each
yield self
end
end

Lets you enumerate without having to worry about whether or not you have
a
collection. Thoughts? Hidden ramifications?

On Tue, Nov 30, 2010 at 12:44 PM, Andrew W.
[email protected]wrote:

Ugh, did I just say collection? I thought my .Net days were behind
me…I
meant, of course, an enumerable…

On 11/30/2010 06:45 PM, Andrew W. wrote:

Lets you enumerate without having to worry about whether or not you have a
collection. Thoughts? Hidden ramifications?

First of all if you implement #each then you should also include
Enumerable because the expectation would be that you also have all the
nice methods like #select, #map etc. This makes all objects Enumerable
which does not seem a good idea. One drawback of this approach is that
you won’t notice if you accidentally pass something to a method which
should be Enumerable (I mean a real collection) - or at least the issue
might take some time to be detected.

Ugh, did I just say collection? I thought my .Net days were behind me…I
meant, of course, an enumerable…

:slight_smile:

Cheers

robert

On Tue, Nov 30, 2010 at 4:40 PM, Robert K.
[email protected]wrote:

end
seem a good idea.
An interesting point. I think I agree that cluttering Object with all
the
Enumerable methods seems like a bad idea. I guess my thinking was that
this
would be useful just for the purposes of having #each available, without
including Enumerable. This avoids the [*items] garbage.

One drawback of this approach is that you won’t notice if you accidentally
pass something to a method which should be Enumerable (I mean a real
collection) - or at least the issue might take some time to be detected.

This is an interesting argument, because it sounds an awful lot like
the
arguments I usually hear against duck-typing and dynamic typing in
general.
Don’t those also allow issues which “might take some time to be
detected”
too? It seems like the answer is, as always, that’s what specs/tests are
for.

One other thing that I thought of after my original email is that it
might
be preferable to change it to “yield self unless nil?”, because it could
be
odd to have NilClass#each.

Thanks for the thoughts!

On Wed, Dec 1, 2010 at 12:00 AM, Andrew W. [email protected]
wrote:

class Object
because the expectation would be that you also have all the nice methods
like #select, #map etc. This makes all objects Enumerable which does not
seem a good idea.

An interesting point. I think I agree that cluttering Object with all the
Enumerable methods seems like a bad idea. I guess my thinking was that this
would be useful just for the purposes of having #each available, without
including Enumerable. This avoids the [*items] garbage.

I usually opt for making things explicit - at least if they are so
clutterless as “[*items]”. :slight_smile:

One drawback of this approach is that you won’t notice if you accidentally
pass something to a method which should be Enumerable (I mean a real
collection) - or at least the issue might take some time to be detected.

This is an interesting argument, because it sounds an awful lot like the
arguments I usually hear against duck-typing and dynamic typing in general.
Don’t those also allow issues which “might take some time to be detected”
too? It seems like the answer is, as always, that’s what specs/tests are
for.

Hm, not sure I agree. With duck typing you will immediately know if
an object does not implement a required method. Granted, you can pass
in all objects that satisfy the used contract without “noticing”. But
then again that’s the whole point of duck typing. :slight_smile: Maybe my
argument is not too important though. The main point would be anyway
the first argument against, that then everything is Enumerable and the
module Enumerable basically becomes meaningless.

One other thing that I thought of after my original email is that it might
be preferable to change it to “yield self unless nil?”, because it could be
odd to have NilClass#each.

No. You would simply use inheritance and implement a special version
in class NilClass which throws, e.g.

class NilClass
def each
raise NoMethodError, “undefined method each for %p” % self
end
end

Thanks for the thoughts!

You’re welcome! It’s an interesting exchange.

Kind regards

robert

Consider code like this:

def do_sth_on(this)
if this.kind_of?(Enumerable)
this.map {|item| do_sth_on(item) }
else
# whatever
end
end

This is a method that either works on a collection or on single item. As
soon as a you make Object behave like Enumerable, this breaks and leads
to recursion.
Always very dangerous to modify core classes and in this case it seems
suicidal :slight_smile:

– niklas

On Wed, Dec 1, 2010 at 8:52 AM, niklas | brueckenschlaeger <
[email protected]> wrote:

This is a method that either works on a collection or on single item. As
soon as a you make Object behave like Enumerable, this breaks and leads
to recursion.

Well, sure. The whole point is to write, instead of the above:

def do_sth_on(this)
this.each do
#whatever
end
end

On Wed, Dec 1, 2010 at 8:30 AM, Andrew W.
[email protected]wrote:

end
end

I think he means that you remove the base case that recursive functions
may
be relying on. Here is an example:

a function, maybe in a lib you are using,

silently doing its job, you don’t even know its there

to do its job it must recursively traverse enumerable objects

in this example, it just prints them out

def print_nested(iteratable)
iteratable.each do |*objects|
if objects.size > 1
print_nested(objects)
next
end
object = objects.first
if object.respond_to? :each
print_nested object
else
puts object
end
end
end

prints 1 through 16

print_nested [
1,2,[3,4,[5]],
{ 6 => 7,
8 => [ 9 , 10 , { 11 => 12…14 } ]
},
“15\n16”,
]

make everything respond to each

class Object
def each
yield self
end
end

stack overflow

print_nested [
1,2,[3,4,[5]],
{ 6 => 7,
8 => [ 9 , 10 , { 11 => 12…14 } ]
},
“15\n16”,
]