Ruby generators vs Python generators
Asked Answered
U

3

20

I've been researching the similarities/differences between Ruby and Python generators (known as Enumerators in Ruby), and so far as i can tell they're pretty much equivalent.

However one difference i've noticed is that Python Generators support a close() method whereas Ruby Generators do not. From the Python docs the close() method is said to do the following:

Raises a GeneratorExit at the point where the generator function was paused. If the generator function then raises StopIteration (by exiting normally, or due to already being closed) or GeneratorExit (by not catching the exception), close returns to its caller."

Is there a good reason why Ruby Enumerators don't support the close() method? Or is it an accidental omission?

I also discovered that Ruby Enumerators support a rewind() method yet Python generators do not...is there a reason for this too?

Thanks

Unset answered 25/9, 2010 at 17:25 Comment(4)
Curious, but I don't understand how you'd use this: can you give an example?Sibell
@Andrew Vit: this can be used to cause resources —database connections, files, etc.— held by the generator to be cleaned up. It will also prevent any further calls to its next or send methods from other parts of the code. You could call close, for example, to indicate from one of a number of consumers to indicate to others that a desired value has been found.Postlude
@intuited, is Python's close() actually commonly used though? I think i read somewhere that it's considered 'arcane' by the python community and not really utilized.Unset
close() is part of the API for carrying out two-way communication with the generator, turning it into a "co-routine". You can read about it in python.org/dev/peps/pep-0342. Does Ruby have that concept?Froebel
B
7

This documentation for the rewind method is a little scarce on details. But in order to "start over" the generator would have to do one of two things:

  • remember its complete output, repeat that output once rewound, then resume what it was doing before
  • reset its internal state in a way that causes the same output to be repeated without other unwanted side effects

The second of these is not always possible; for example, if the generator emits byte buffers from the network, the output is not entirely a function of internal state. But any generator that uses the first technique must necessarily build up a larger and larger buffer in memory as it is used. Such generators offer little performance benefit over lists.

Therefore, I conclude that the Ruby rewind method must be optional and not always supported by a concrete enumerator class. So if the Python designers value the Liskov substitution principle, that would lead them not to require such a method in all generators.

Brat answered 28/6, 2012 at 18:2 Comment(0)
S
2

Generators are stack based, Ruby's Enumerators are often specialised (at the interpreter level) and not stack based.

Slesvig answered 26/9, 2010 at 1:25 Comment(0)
E
1

Ruby's Enumerator's use StopIteration class internally, see How do Enumerators work in Ruby 1.9.1?

(it's just wrapped if you use it in a for each call). So I'd say they'are a rather close. That being said, I'm not sure what a close method on an enumerator should do, exactly...cleanup, perhaps? (Python's generators probably would benefit from a rewind--note well that in Ruby, some enumerators don't respond to rewind, so they raise an exception when you call that method).

Euhemerus answered 29/9, 2010 at 19:49 Comment(2)
thanks for your answer. But StopIteration is what python uses too - in fact Ruby took this idea from Python hehe. As Regards what a close() might do, look to intuited's comment to my question (above).Unset
yeah ruby 1.9.x's Enumerator basically brought it into line with Python's Generator (though you can also just use a block in Ruby to simulate a generator, really).Euhemerus

© 2022 - 2024 — McMap. All rights reserved.