--- Michael Lazzaro <[EMAIL PROTECTED]> wrote:
>
> On Wednesday, May 28, 2003, at 01:01 PM, Austin Hastings wrote:
> > Exampling:
> >
> > sub traverse(Hash $tree) {
> > return unless $tree;
> >
> > traverse $tree{left} if $tree{left};
> > yield $tree{node};
> > traverse $tree{right} if $tree{right};
> > }
> >
> > my %hash is Tree;
> > my &cotrav := coro &traverse(%hash);
> > print $_ for <ctrav.resume>;
> >
> > my &thtrav := thread &traverse(%hash);
> > print $_ for <thtrav.resume>;
>
>
> Hmm. I think that having _anything_ on the caller side that has to
> change based on whether the called thing is a subroutine vs. a
> coroutine probably defeats one of the most central purposes of
> coroutines -- that nifty subroutine-like abstraction that makes it
> "just work". Consider, under Damian's latest model:
>
> for <foo()> {...}
>
> It doesn't matter whether foo() is a closure or function returning a
> list, lazy list, or iterator, or is a coroutine returning it's .next
> value. Which is excellent, and, I'd argue, the whole point; I'm not
> sure that we can have any coroutine syntax that _doesn't_ do that,
> can we?
Given that I can say:
sub do_foo {...}
my &foo := coro &do_foo;
I can still provide the "transparent" behavior you're wanting.
> But, as Luke pointed out, some of the other syntax required to make
> that work is isn't particularly friendly:
>
> coro pre_traverse(%data) {
> yield %data{ value };
> yield $_ for <&_.clone(%data{ left })>;
> yield $_ for <&_.clone(%data{ right })>;
> }
> If I work backwards, the syntax I'd _want_ for something like that
> would be much like Luke proposed:
>
> sub pre_traverse(%data) is coroutine {
> yield %data{ value };
> pre_traverse( %data{ left } );
> pre_traverse( %data{ right } );
> }
>
> ... where the internal pre_traverses are yielding the _original_
> pre_traverse. Whoa, though, that doesn't really work, because you'd
> have to implicitly do the clone, which screws up the normal iterator
> case! And I don't immediately know how to have a syntax do the right
> thing in _both_ cases.
>
> So, if I have to choose between the two, I think I'd rather iteration
> be easy than recursion be easy. If lines like
>
> yield $_ for <&_.clone(%data{ left })>;
>
> are too scary, we might be able to make a keyword that does that,
> like:
>
> sub pre_traverse(%data) is coroutine {
> yield %data{ value };
> delegate pre_traverse( %data{ left } );
> delegate pre_traverse( %data{ right } );
> }
>
> Maybe. But in truth, that seems no more intuitive than the first.
Q: Can you "yield" from a subsubroutine?
If no, then yield=>coro at compile time. I don't care much for this
because it puts too much emphasis on remaining "in" the coroutine,
precluding me from distributing functionality. John MacDonald has given
several examples of this.
Q: If you recurse, does it automatically create a new coro context?
If Yes: We need a way to recurse in context. Perhaps by saying
&_.recurse(...) ?
If No: How do you create a new context?
Perhaps we need both: coro-as-verb to create a coro context on any
arbitrary function, and coro-as-type to declare contexts in advance.
>
> (s/coroutine/thread/g for the same rough arguments, e.g. "why should
> the caller care if what they're doing invokes parallelization, so
> long as it does the right thing?")
Global variables. Threads __never__ do the right thing.
=Austin