arc_of_descent has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I've thought about both these options, but just can't decide on which to go with and why. i.e. what are the drawbacks or advantages of choosing one over the other.

Please see this code. The Feed object implements an iterator to cycle through a list of feeds.

This is via a Class method

use Feed; while (my $feed = Feed->next) { $feed->fetch(); }

Here, the next method implements an iterator and returns a new Feed object. The first time the next method is called, it may need to do some initializing stuff, like maybe connecting to a database.

This is using an object method

use Feed; my $feed = Feed->new; while ($feed->set_next) { $feed->fetch; }

In this case, I use the new method to initialize and create a Feed object. The set_next method cycles through the list of feeds, and sets variables of the current Feed object. What I like about this option, is that the new method is separate from the Iterator.

Any criticisms of a particular choice?

Thanks!


--
Rohan

Replies are listed 'Best First'.
Re: Iterator as a Class or Object Method
by Zaxo (Archbishop) on Oct 03, 2005 at 04:04 UTC

    An iterator needs to keep some metadata around to know where it is in the data feed. That poses problems for both your ideas. A class method needs lots of internal bookkeeping to distinguish between calls for one instance and another. It will be a poor choice.

    An instance method needs bookkeeping to distinguish between one depth of loop and another in nested iteration. Like Perl's each hash iterator, most implementations don't bother, and just live with the restriction to a single loop.

    The general solution is to make the iterator an object of its own. Here's an incomplete sketch,

    package Feed::Iterator; sub new { my ($class, $feed) = @_; my $self = _init($feed); bless $self, $class; } sub gimme { # . . . } package Feed; sub iter { my $self = shift; Feed::Iterator->new($self) }
    That way you have a Feed instance method which returns a Feed::Iterator object that keeps its own state. The bookkeeping is shoved off onto the perl call stack where it belongs.

    See Limbic~Region's tutorial How To: Make An Iterator for all the fine details.

    After Compline,
    Zaxo

Re: Iterator as a Class or Object Method
by NetWallah (Canon) on Oct 03, 2005 at 04:41 UTC
    In a situation like you describe, you can frequently use a callback to achieve the result you want.

    You simply pass in a subref of code you want executed for each iteration, and let the object instance method do the iteration work, and call your subref as necessary.

         "Man cannot live by bread alone...
             He'd better have some goat cheese and wine to go with it!"

      I agree wholeheartedly with BUU. I'm rewriting Tree::Simple right now and I completely removed the visitor interface for exactly that reason. I'll give you an iterator over me and my children and you can implement the visitor interface if it's that important to you.

      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
        Care to explain? Seems like you are against "map", "grep", and "foreach" (i.e. pass a block to a higher order function). Maybe I'm misunderstanding what a "visitor" is?
      Please, for the love of god, File::Find is bad enough, we don't need any more modules using this hideous interface.
        Please, for the love of god, File::Find is bad enough, we don't need any more modules using this hideous interface.

        I agree that Find::File is foul - but that's more because of bad design rather than something bad with callback based APIs in general. If it passed named arguments rather than using evil globals it would be a fair bit nicer to use.

        I'm hearing unsupported objections to passing coderefs to objects.

        I will concede that this is not for the feint-of-heart - newbies find it difficult to fathom the concept, so, writers shouls probably provide an alternative interface for common goodies like File::Find.

        The larger issue, as I see it, is that coderefs provide an elegant solution such as this one. Plenty of modules use filters as properties - either as regexen or coderefs.

        To simplify caller understanding, I usually provide an alternative of pre-specifying the code-ref as an object property, then calling a method that will invoke the coderef.

        Beyond personal preferences, and perceived complexity, is there a reason NOT to use coderefs ?

             "Man cannot live by bread alone...
                 He'd better have some goat cheese and wine to go with it!"

Re: Iterator as a Class or Object Method
by pg (Canon) on Oct 03, 2005 at 04:16 UTC

    Making the iterator a method specific to any particular class or instance of class is against the basic idea of OO. Iteration itself is a concept detached from any specific existance. To make it a method simply restricts its reusability.

    If you are so fond of making this OO, there should be an Iterator base class, which defines certain common methods like next(). This class should NOT be a sub class of any of your other classes.

    You can inherit from this base class and add methods that are specfic to your needs.