The Block Returns

2003-10-02 Thread Luke Palmer
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

2003-10-02 Thread Stefan Lidman
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

2003-10-02 Thread Luke Palmer
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

2003-10-02 Thread Dave Mitchell
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

2003-10-02 Thread Jonathan Scott Duff

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

2003-10-02 Thread Mark A. Biggar
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

2003-10-02 Thread Austin Hastings
> -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

2003-10-02 Thread Jeff Clites
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

2003-10-02 Thread Luke Palmer
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

2003-10-02 Thread Austin Hastings


> -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

2003-10-02 Thread Luke Palmer
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
>   
>