in reply to RFC Magic::Attach

I wonder if this couldn't be used for implementing co-routines. I started thinking about it and remembered a post by Ovid on the subject.

Here's what I am thinking and I am sure there are flaws and other issues problems I haven't thought of. You use attach_var() to create persistant arguments for the sub. (This could be wrapped in a routine, say persist(); This would just be syntactical sugar for $var = attached(blahblah} or attach_var(blabla);

You have a sub called yield that takes a block as an argument. It computes a "context key" from the caller info. It checks to see if it the calling sub has a "context stash" associated with it. This would be an array of contexts. If not it creates one (attached to the calling sub) and pushes an empty context.

It could then check to see if had been called already in this context. (With the same args, from the same line in source.)

If it has it returns. Basically a NOOP.

If it hasn't, it marks itself as being called in the stash and pushes a new context on the "context stack", it then executes the block.

You then have a sub called yield_return(). This pops the context off of the stack and returns.

It would look a little something like this. (Using TheDamians example at http://www.yetanother.org/damian/Perl5+i/coroutines.html)
package Tree; sub next_inorder{ my $self = persist(); yield { $self->{left}->next_inorder } if $self->{left} +; yield { $self }; yield { $self->{right}->next_inorder if } $self->{righ +t}; yield_return undef; } # and later... while (my $node = $root->next_inorder()) { print $node->{data}; }
Anyone see a flaw or potential snags with this attack?

-Lee

"To be civilized is to deny one's nature."

Replies are listed 'Best First'.
Re: Magic::Attach & Co-routines?
by adrianh (Chancellor) on Jan 21, 2003 at 14:48 UTC
    Anyone see a flaw or potential snags with this attack?

    Co-routines that call co-routines are where it gets tricky for the algorithm you outlined. Consider this line in your example:

    yield { $self->{left}->next_inorder } if $self->{left};

    next_inorder is called recursively, and the context of yielding a yielded result should leave the execution within the recursive call to next_inorder.

    You could make this example work by differentiating between a yielded result and a normal return. However, once you have code that has side effects it starts getting hard.