tags:

views:

110

answers:

3

I have an iterator with this interface: $hit->next_hsp

The current implementation to listify it is:

my @list;
while ( my $hsp = $hit->next_hsp ) {
    push( @list, $hsp );
}

Now I'm thinking that there might be better ways to do this in less code. What do you say, stackers?

+3  A: 

It entirely depends on the iterator implementation. If next_hsp is the only available method, then you're doing it right.

Pedro Silva
+5  A: 

All iterators I've ever seen return undef to signify that they are exhausted. Therefore you should write while (defined(my $hsp = $hit->next_hsp)). The following example demonstrates the fault in the question which tests for truth (aborts at 1) instead of definedness (passes 'liftoff').

use 5.010;
my $hit = __PACKAGE__;

sub next_hsp {
    state $i;
    $i++;
    return ['mumble', 4, 3, 2, 1, 0, 'liftoff']->[$i];
}

# insert snippet from question here
daxim
That is a good point. It makes the entire thing even more unwieldy, but you are right.
Mithaldu
A common pattern is for an iterator to simply `return` with no args at the end. In a scalar context that turns into `undef` but if you say `my($hsp) = $hit->next_hsp` then the iterator can safely return a value of undef (or anything else that might be interpreted as false) in cases where it makes sense to do so. This works because a list containing 1 value will be boolean true regardless of whether the value is false or even undef.
Grant McLean
All iterators? I've seen quite a number that are infinite. :)
brian d foy
+3  A: 

Don't worry about playing golf, the code you have looks just fine (other than the other answers about using defined). However, if you find yourself repeating this pattern 2 things come to mind.

The first is obvious, refactor it into a utility function, so that you have my @list = expand($hit).

The second question is a bit deeper - but to me smells more than playing golf. The whole point of iterators is to consume as you need them, so if you find yourself doing this often, are you sure it's really the right thing to do? Perhaps your moving this data outside your own API, so you're constrained to other's choices, but if you have the option of consuming an iterator rather than a list, maybe this will be a cleaner solution.

aCiD2