Enumerable#to_a can run forever

B

Benjamin Kudria

It's possible to implement an each method in a class mixing in
Enumerable that runs forever, and thus causing, for example, to_a to run
forever. One such class is mathn's Prime class:

require 'mathn'
Prime.new.to_a # <- runs forever, never returns

This seems a bit broken to me, and I was writing a program where I
needed the first n primes, or all the primes under 200, for example, so
I re-wrote Enumerable#to_a like so to make my code more idiomatic:

----8<----
module Enumerable
def to_a(n = nil)
result = []
inclusion_condition = true
return result if n.to_i <= 0 and !block_given?
each do |*elements|
elements = elements.first if elements.size == 1
if block_given?
values = result.last
inclusion_condition = yield(*values) unless values.nil?
else
inclusion_condition = n != result.size
end

if inclusion_condition
result << elements
else
result.pop if block_given?
break result
end
end
result
end
end
----8<----

This allows, for example, the following:
Prime.new.to_a(10) # => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] , the first
10 primes
Prime.new.to_a {|prime| prime < 20} # => [2, 3, 5, 7, 11, 13, 17, 19] ,
all the primes under 20

Passed an integer paramater, the code will return an array that long, or
until the Enumerable runs out. Passed a block, it will return an array
of elements, adding elements until the block evaluates to false.

This code surely could use some hacking, refactoring, and possibly bug
fixing. I've made a post[1] on http://refactormycode.com just for that
purpose.

Thoughts?

[1]
http://refactormycode.com/codes/196-enumerable-to_a-with-terminating-conditions

-Ben Kudria
 
B

Benjamin Kudria

Yukihiro said:
Hmm, in 1.9, you have Enumerable#take to work like your to_i(num), and
Enumerable#take_while like your to_i{...}.

p Prime.new.take(10) # => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
p Prime.new.take_while{|prime| prime < 20} # => [2, 3, 5, 7, 11, 13,
17, 19]

matz.

Aaah, ok. Those would be excellent. I look forward to 1.9! Thank you!
However, what about Prime.new.to_a ? That would still run forever, and
the unsuspecting coder might be caught by surprise.
 
B

Benjamin Kudria

Yukihiro said:
It's no way to avoid entering infinite loop when you do some
operations on infinite enumerable, such as Prime. For example, trying
#sort or #max on Prime, or even putting it as a splat will cause
infinite loop. Adding an argument or a block to #to_a does not
improve the situation a lot, I think.

matz.

Fair enough - but then does it make sense to have these operations
defined?
Enumerable seems to mean the same thing as "countable", but it includes
methods that apply to only countably finite sets. Perhaps there should
be a way to distinguish between sets that are countable finite and those
that are countably infinite? Does 1.9 include provisions for handling
infinite lists or sets?

Thanks,
Ben Kudria
 
B

Benjamin Kudria

Yukihiro said:
|Fair enough - but then does it make sense to have these operations
|defined?

Because it's very pragmatically useful for most of the case.
Theoretical cleanliness is not my concern.

Aah, I see. I guess I agree.
|Perhaps there should
|be a way to distinguish between sets that are countable finite and those
|that are countably infinite?

And adding one burden to library implementer (including me)?

Fair enough :). It would probably be overly confusing for the coder,
too.
|Does 1.9 include provisions for handling
|infinite lists or sets?

I think you mean generator. If so, it has been supported since 1.8.

You are correct, I see Generators in 1.8 can do everything I want.
Seems I don't know Ruby as well as I thought. :)

Thanks for clarifying everything.

Ben Kudria
 

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,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top