The Block Returns
So, I must ask, what does this do: sub foo() { return my $self = { print "Block"; return $self; } } my $block = foo; print "Main"; $block(); print "End"; That is, the block returns from a function that's not currently executing. Will the output be: a) Can't 'return' from closure Block b) Main Block Can't 'return' from closure Block (just like (a) but runtime) c) Main Block (the block's return returns from the main program, or whatever function is currently executing) d) Main Block Main Block Main Block ... (the block closes over the function's return continuation) (a) and (b) both sound pretty good. (c) is a very bad idea, as it's very subtle, breaks return type safety, introduces unexpected control flow, etc. We'll leave those responsibilites to C :-) Maybe (d) is the way we slip in continuations without anyone noticing. It's the only one of these possibilites that works intuitively with, eg. "grep". It still seems like it might too easily introduce subtle bugs. Is there another meaningful possibility that I didn't cover? I've heard Smalltalk has something equivalent to the sub/block distinction; what does it do? Luke
Re: The Block Returns
So, I must ask, what does this do: >sub foo() { >return my $self = { >print "Block"; >return $self; >} >} >my $block = foo; # = sub {print "Block"; return $self;} A6: One obvious difference is that the sub on closures is now optional, since every brace-delimited block is now essentially a closure. You can still put the sub if you like. But it is only required if the block would otherwise be construed as a hash value; that is, if it appears to contain a list of pairs. >print "Main"; >$block(); >print "End"; >That is, the block returns from a function that's not currently >executing. Main Block End is my guess. /Stefan
Re: The Block Returns
Stefan Lidman writes: > So, I must ask, what does this do: > > >sub foo() { > >return my $self = { > >print "Block"; > >return $self; > >} > >} > > >my $block = foo; > # = sub {print "Block"; return $self;} > > A6: > One obvious difference is that the sub on closures is now optional, > since every brace-delimited block is now essentially a closure. You > can still put the sub if you like. But it is only required if the > block would otherwise be construed as a hash value; that is, if it > appears to contain a list of pairs. Um, yeah, but just a little farther down: Although we say the sub keyword is now optional on a closure, the return keyword only works with an explicit sub. (There are other ways to return values from a block.) And to clarify: sub indexof(Selector $which, [EMAIL PROTECTED]) { for zip(@data, 0...) -> $_, $index { when $which { return $index } } } Which actually creates a closure (well, in theory at least) on line 2 for the for loop, but the return inside of it returns from indexof. Which is actually very, very nice. So the question is: What happens when indexof isn't on the call chain, but that inner closure is? Luke > >print "Main"; > >$block(); > >print "End"; > > >That is, the block returns from a function that's not currently > >executing. > > Main > Block > End > > is my guess. > > /Stefan
Re: The Block Returns
On Thu, Oct 02, 2003 at 04:15:06AM -0600, Luke Palmer wrote: > And to clarify: > > sub indexof(Selector $which, [EMAIL PROTECTED]) { > for zip(@data, 0...) -> $_, $index { > when $which { return $index } > } > } > > Which actually creates a closure (well, in theory at least) on line 2 > for the for loop, but the return inside of it returns from indexof. > Which is actually very, very nice. > > So the question is: What happens when indexof isn't on the call chain, > but that inner closure is? But how can the inner closure be called if not via indexof? -- To collect all the latest movies, simply place an unprotected ftp server on the Internet, and wait for the disk to fill
Re: The Block Returns
On Thu, Oct 02, 2003 at 11:39:20AM +0100, Dave Mitchell wrote: > On Thu, Oct 02, 2003 at 04:15:06AM -0600, Luke Palmer wrote: > > So the question is: What happens when indexof isn't on the call chain, > > but that inner closure is? > > But how can the inner closure be called if not via indexof? I believe that's exactly what Luke's original example was illustrating. On Thu, Oct 02, 2003 at 01:59:26AM -0600, Luke Palmer wrote: > So, I must ask, what does this do: > > sub foo() { > return my $self = { > print "Block"; > return $self; > } > } foo() returns a closure that contains code that returns from the foo() subroutine (the line that says "return $self") When that closure is then called ... > my $block = foo; > print "Main"; > $block(); ... foo() is no longer executing. > That is, the block returns from a function that's not currently > executing. > > Will the output be: a) > > Can't 'return' from closure Block > > b) > > Main > Block > Can't 'return' from closure Block > > (just like (a) but runtime) > c) > > Main > Block > > (the block's return returns from the main program, or whatever function > is currently executing) > > d) > > Main > Block > Main > Block > Main > Block > ... > > (the block closes over the function's return continuation) I would expect (a) to happen, but (d) has some interesting possibilities. And wouldn't (d) be: Main Block Block Block ... ? Actually, if your last parenthetical were true, it would be Main Block End because though foo()'s return continuation is closed over, it only gets executed once and then returned. I.e., to get "Block" again, you'd need to execute the return value of $block. my $block = foo; print "Main"; $b2 = $block(); $b3 = $b2(); $b4 = $b3();# etc. print "End"; or for the infinite version: my $block = foo; print "Main"; $block = $block() while 1; print "End";# we never get here Or am I missing something? -Scott -- Jonathan Scott Duff [EMAIL PROTECTED]
Re: The Block Returns
Jonathan Scott Duff wrote: On Thu, Oct 02, 2003 at 11:39:20AM +0100, Dave Mitchell wrote: On Thu, Oct 02, 2003 at 04:15:06AM -0600, Luke Palmer wrote: So the question is: What happens when indexof isn't on the call chain, but that inner closure is? But how can the inner closure be called if not via indexof? I believe that's exactly what Luke's original example was illustrating. On Thu, Oct 02, 2003 at 01:59:26AM -0600, Luke Palmer wrote: So, I must ask, what does this do: sub foo() { return my $self = { print "Block"; return $self; } } foo() returns a closure that contains code that returns from the foo() subroutine (the line that says "return $self") When that closure is then called ... my $block = foo; print "Main"; $block(); ... foo() is no longer executing. That is, the block returns from a function that's not currently executing. Will the output be: a) Can't 'return' from closure Block b) Main Block Can't 'return' from closure Block (just like (a) but runtime) c) Main Block (the block's return returns from the main program, or whatever function is currently executing) d) Main Block Main Block Main Block ... (the block closes over the function's return continuation) I would expect (a) to happen, but (d) has some interesting possibilities. And wouldn't (d) be: Main Block Block Block ... ? Actually, if your last parenthetical were true, it would be Main Block End because though foo()'s return continuation is closed over, it only gets executed once and then returned. I.e., to get "Block" again, you'd need to execute the return value of $block. my $block = foo; print "Main"; $b2 = $block(); $b3 = $b2(); $b4 = $b3();# etc. print "End"; or for the infinite version: my $block = foo; print "Main"; $block = $block() while 1; print "End"; # we never get here Or am I missing something? Possibly, I brought a similar example to Larry a while ago and he said that creating a closuer and assigning to a variable (or even returning it), may need to be an exception to the "sub" required for "return" rule, exactly because of this dangling context problem. So in the above example, the return is from the local closure not the from foo(). -- [EMAIL PROTECTED] [EMAIL PROTECTED]
RE: The Block Returns
> -Original Message- > From: Jonathan Scott Duff [mailto:[EMAIL PROTECTED] > On Thu, Oct 02, 2003 at 11:39:20AM +0100, Dave Mitchell wrote: > > On Thu, Oct 02, 2003 at 04:15:06AM -0600, Luke Palmer wrote: > > > So the question is: What happens when indexof isn't on the call chain, > > > but that inner closure is? > > > > But how can the inner closure be called if not via indexof? > > I believe that's exactly what Luke's original example was > illustrating. > > On Thu, Oct 02, 2003 at 01:59:26AM -0600, Luke Palmer wrote: > > So, I must ask, what does this do: > > > > sub foo() { > > return my $self = { > > print "Block"; > > return $self; > > } > > } > > foo() returns a closure that contains code that returns from the foo() > subroutine (the line that says "return $self") When that closure is > then called ... > > > my $block = foo; > > print "Main"; > > $block(); > > ... foo() is no longer executing. > > > That is, the block returns from a function that's not currently > > executing. > > > > Will the output be: a) > > > > Can't 'return' from closure Block > > > > b) > > > > Main > > Block > > Can't 'return' from closure Block > > > > (just like (a) but runtime) > > c) > > > > Main > > Block > > > > (the block's return returns from the main program, or whatever function > > is currently executing) > > > > d) > > > > Main > > Block > > Main > > Block > > Main > > Block > > ... > > > > (the block closes over the function's return continuation) > > I would expect (a) to happen, but (d) has some interesting > possibilities. I hope not. Otherwise the ability to use anonymous blocks would be severely impaired. If there's a list of keywords that can't be used in anonymous blocks, that's a pretty severe limitation. And really, is this any worse than an anonymous block that throws exceptions? Speaking to the practical side, I have written code that has to disentangle itself from the failure of a complex startup sequence. I'd love to be able to build a dynamic exit sequence. (In fact, being able to do &block .= { more_stuff(); }; is way up on my list...) =Austin
Re: The Block Returns
Speaking to the practical side, I have written code that has to disentangle itself from the failure of a complex startup sequence. I'd love to be able to build a dynamic exit sequence. (In fact, being able to do &block .= { more_stuff(); }; is way up on my list...) I've wanted to do that sort of thing before, but it seems simpler (conceptually and practically) to build up an array of cleanup subs/blocks to execute in sequence, rather than to have a .= for blocks. (Another reason it's handy to keep them separate is in cases in which each needs to return some information--maybe a status which determines whether to proceed, etc.) JEff
Re: The Block Returns
Jeff Clites writes: > >Speaking to the practical side, I have written code that has to > >disentangle > >itself from the failure of a complex startup sequence. I'd love to be > >able > >to build a dynamic exit sequence. (In fact, being able to do &block > >.= > >{ more_stuff(); }; is way up on my list...) > > I've wanted to do that sort of thing before, but it seems simpler > (conceptually and practically) to build up an array of cleanup > subs/blocks to execute in sequence, rather than to have a .= for > blocks. (Another reason it's handy to keep them separate is in cases in > which each needs to return some information--maybe a status which > determines whether to proceed, etc.) But this is already supported, in its most powerful form: wrap &block: { call; other_stuff() } Luke
RE: The Block Returns
> -Original Message- > From: Luke Palmer [mailto:[EMAIL PROTECTED] > Sent: Thursday, October 02, 2003 10:23 PM > To: Jeff Clites > Cc: [EMAIL PROTECTED]; [EMAIL PROTECTED] > Subject: Re: The Block Returns > > > Jeff Clites writes: > > >Speaking to the practical side, I have written code that has to > > >disentangle > > >itself from the failure of a complex startup sequence. I'd love to be > > >able > > >to build a dynamic exit sequence. (In fact, being able to do &block > > >.= > > >{ more_stuff(); }; is way up on my list...) > > > > I've wanted to do that sort of thing before, but it seems simpler > > (conceptually and practically) to build up an array of cleanup > > subs/blocks to execute in sequence, rather than to have a .= for > > blocks. (Another reason it's handy to keep them separate is in cases in > > which each needs to return some information--maybe a status which > > determines whether to proceed, etc.) > > But this is already supported, in its most powerful form: > > wrap &block: { call; other_stuff() } Hmm, no. That does a call, which presumes a return, which burns up who-knows-how-many mips. Given that the compiler is being forced to remember the code in case someone overloads the semicolon operator, or whatever, I don't think it's unreasonable to catenate the .source values of various blocks, and that seems a reasonable behavior for infix:.=(Block, Block) {...}. Especially since the other way turns into: macro atexit(Block $b) { get_the_current_sub().eval("my &block = {};") unless defined █ wrap &block: { call; $b(); }; } Which makes two calls per additional whosit. Frankly, I think I'd rather see: macro atexit($code) is parsed(/{ * }/) { get_the_current_sub().eval("my $block;") unless defined $block; $block .= $code; } macro return($retval) { eval($block) if defined $block; leave Routine, $retval; } But that imposes eval() pretty frequently. Better to provide some lower-level hackish way to agglutinate Blocks. =Austin
Re: The Block Returns
Austin Hastings writes: > > -Original Message- > > From: Luke Palmer [mailto:[EMAIL PROTECTED] > > > > But this is already supported, in its most powerful form: > > > > wrap &block: { call; other_stuff() } > > Hmm, no. > > That does a call, which presumes a return, which burns up > who-knows-how-many mips. Given that the compiler is being forced to > remember the code in case someone overloads the semicolon operator, or > whatever, I don't think it's unreasonable to catenate the .source > values of various blocks, and that seems a reasonable behavior for > infix:.=(Block, Block) {...}. Oh... so that's the reason. Well, you can give up hope on that, I'm pretty sure. If you want to do something like that, mess with the text and eval yourself. The reason is this: my &code := { my $x = "Hello"; print $x; } { my $x = "World"; &code ~= { print $x } } In any sane way of doing things, this should print HelloWorld. That means that your new appended block has to push the registers and load up a new scratchpad just like any closure would. The only thing you're saving is a jump to the proper address, which is mostly negligible. > Especially since the other way turns into: > > macro atexit(Block $b) { > get_the_current_sub().eval("my &block = {};") > unless defined █ > wrap &block: { call; $b(); }; > } I really haven't the slightest idea what that's supposed to mean. Where'd &block come from? What does Code.eval(String) mean? > Which makes two calls per additional whosit. > > Frankly, I think I'd rather see: > > macro atexit($code) is parsed(/{ * }/) { > get_the_current_sub().eval("my $block;") > unless defined $block; > $block .= $code; > } > > macro return($retval) { > eval($block) if defined $block; > leave Routine, $retval; > } > > But that imposes eval() pretty frequently. Better to provide some lower-level > hackish way to agglutinate Blocks. And you suggest that this low-level hackish way is with a common operator, like C<~>. Oh, that's brilliant. Luke > > =Austin > >