Enumerators == Resource Leak Risk?

Discussion in 'Ruby' started by keithrbennett, Mar 21, 2014.

  1. I've recently been writing custom Enumerable classes, and thought it would be a good idea to support Enumerators as well. Making an Enumerable Enumerator-enabled seems to be as simple as adding the following line to the beginning of each():

    return to_enum unless block_given?

    However, I realized that I might be introducing a risk of resource leaks bydoing so. For example, if my enumerable opens a file to read from, and I read a few but not all values from an enumerator it gives me, then the Enumerable's each() method that feeds Enumerator's next method never completes, and the file close there is never executed.

    Should I *not* support enumerators if this is the case?

    My current workaround is to define a new 'close' method on the Enumerator returned by super.to_enum (see to_enum() call at https://github.com/keithrbennett/trick_bag/blob/master/lib/trick_bag/enumerables/file_line_reader.rb for an example). I then call the 'close' method when I'm done calling the enumerator's 'next' method.

    In that trick_bag gem I have a FilteredEnumerable that can decorate (specifically, filter) enumerators (at https://github.com/keithrbennett/tr.../trick_bag/enumerables/filtered_enumerable.rb). I'm thinkingof adding a close to that enumerator too that calls the wrapped enumerator's close method if it exists:

    def close
    wrapped_enumerator.close if wrapped_enumerator.respond_to?:)close)

    It would be nice if Ruby's Enumerator class defined a no-op close method sothis wouldn't be necessary.

    A problem with my approach is that I've overridden to_enum to take 1 param instead of 0 params. This could be a problem if someone assumes that can call to_enum on an instance of my enumerable.

    Any insight as to the best way to handle this?

    keithrbennett, Mar 21, 2014
    1. Advertisements

  2. No idea whether it's the best approach but you could remove / invalidate
    all methods which do not use each semantic on the returned Enumerator,
    e.g. :feed, :inspect, :next, :next_values, :peek, :peek_values, :rewind

    Personally I believe the external iteration functionality should be
    separated from the "regular" internal iteration functionality. That way
    a clean separation would be achieved. For me the biggest value in
    to_enum lies in the fact that I can turn any method into an iteration,
    e.g. by doing things like 5.times.map {|x| x * 2}. I cannot remember
    having felt the need for external iteration and if so I would not have
    minded to make it explicit.

    Kind regards

    Robert Klemme, Mar 26, 2014
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.