Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Control flow variables

15 views
Skip to first unread message

Luke Palmer

unread,
Nov 18, 2003, 9:20:52 AM11/18/03
to Language List
I was reading the most recent article on perl.com, and a code segment
reminded me of something I see rather often in code that I don't like.
Here's the code, Perl6ized:

... ;
my $is_ok = 1;
for 0..6 -> $t {
if abs(@new[$t] - @new[$t+1]) > 3 {
$is_ok = 0;
last;
}
}
if $is_ok {
push @moves: [$i, $j];
}
...

I see this idiom a lot in code. You loop through some values on a
condition, and do something only if the condition was never true.
$is_ok is a control flow variable, something I like to minimize. Now,
there are other ways to do this:

if (0..6 ==> grep -> $t { abs(@new[$t] - @new[$t+1]) })
{ ... }

But one would say that's not the cleanest thing in the world.

Python pulled this idiom out in to the syntax (yay them), with C<else>
on loops. The else block on a python loop executes only if you never
broke out of the loop. That's a great idea.

So, in Perl's postmodern tradition, I think we should steal that idea.
I'm a little uneasy about calling it C<else>, though. Maybe C<FINISH>
would do, making the example:

for 0..6 -> $t {
if abs(@new[$t] - @new[$t+1]) > 3 {
last;
}
FINISH {
push @moves: [$i, $j];
}
}

I'd also like to say that while converting the rest of this sub to Perl
6, I realized how much I love the ..^ and ^.. operators. I was
wondering whether people had forgotten about them :-).

Luke

Simon Cozens

unread,
Nov 18, 2003, 9:38:17 AM11/18/03
to perl6-l...@perl.org
fibo...@babylonia.flatirons.org (Luke Palmer) writes:
> I was reading the most recent article on perl.com, and a code segment
> reminded me of something I see rather often in code that I don't like.

The code in question got me thinking too; I wanted to find a cleaner
way to write it, but didn't see one.

> So, in Perl's postmodern tradition, I think we should steal that idea.

I agree, but (as usual) would like to consider whether there's a way
to solve a general problem rather than solving a specific problem by
throwing additional syntax at it. (which sadly seems to be fast becoming
the Perl 6 way)

Given that we've introduced the concept of "if" having a return status:

my $result = if ($a) { $a } else { $b };

Then why not extend this concept and have a return status from other
control structures?

for 0..6 -> $t {
last if abs(@new[$t] - @new[$t+1]) > 3;
} or push @moves: [$i, $j];

Of course, these things have consequences; I'm not sure whether we really
want people saying

push @moves:[$i, $j] unless last if abs(@new[$_]-@new[$_+1])>3 for 0..6;

--
The course of true anything never does run smooth.
-- Samuel Butler

Luke Palmer

unread,
Nov 18, 2003, 10:16:31 AM11/18/03
to Simon Cozens, perl6-l...@perl.org
Simon Cozens writes:
> fibo...@babylonia.flatirons.org (Luke Palmer) writes:
> > I was reading the most recent article on perl.com, and a code segment
> > reminded me of something I see rather often in code that I don't like.
>
> The code in question got me thinking too; I wanted to find a cleaner
> way to write it, but didn't see one.
>
> > So, in Perl's postmodern tradition, I think we should steal that idea.
>
> I agree, but (as usual) would like to consider whether there's a way
> to solve a general problem rather than solving a specific problem by
> throwing additional syntax at it. (which sadly seems to be fast becoming
> the Perl 6 way)

Well... it is and isn't. At first sight, it makes the language look
huge, the parser complex, a lot of syntax to master, etc. It also seems
to me that there is little discrimination when adding new syntax.

But I've come to look at it another way. Perl 6 is doing something
(many things, really) that no other language has done before: making it
very easy to add new syntax to the language.

So modules that introduce new concepts into the language can add new
syntax for them without working with (ugh) a source filter. And some of
these new syntaxes in the "core" language will actually be in standard
modules, if they're not commonly used. Just like traits.

But even when they're not, Perl is a generic, multiparadigm language.
It covers and supports many concepts, and new concepts grafted onto an
existing but unfit syntax make things harder. Humans are pretty good at
syntax. Many times mathematicians make up new syntax when they
introduce a new concept: making it easier to think about, and easier to
recognize.

I'll also point out that FINISH isn't really extra syntax, just extra
vocabulary.

> Given that we've introduced the concept of "if" having a return status:
>
> my $result = if ($a) { $a } else { $b };

Ack! We have? It does make sense if we want to be able to implement
C<if> as a regular sub... I guess. Yuck.

> Then why not extend this concept and have a return status from other
> control structures?
>
> for 0..6 -> $t {
> last if abs(@new[$t] - @new[$t+1]) > 3;
> } or push @moves: [$i, $j];
>
> Of course, these things have consequences; I'm not sure whether we really
> want people saying
>
> push @moves:[$i, $j] unless last if abs(@new[$_]-@new[$_+1])>3 for 0..6;

That's illegal anyway. Can't chain statement modifiers :-)

But a close relative would be possible:

push @moves: [$i, $j] unless for 0..6 { last if abs(@new[$_]-@new[$_+1]) > 3 }

Yeah, how about no. :-)

Luke

Simon Cozens

unread,
Nov 18, 2003, 10:25:56 AM11/18/03
to Luke Palmer, perl6-l...@perl.org
Luke Palmer:

> Well... it is and isn't. At first sight, it makes the language look
> huge, the parser complex, a lot of syntax to master, etc. It also seems
> to me that there is little discrimination when adding new syntax.

Correct.

> But I've come to look at it another way. Perl 6 is doing something
> (many things, really) that no other language has done before: making it
> very easy to add new syntax to the language.

Well, that's hardly a new concept for a programming language.

> So modules that introduce new concepts into the language can add new
> syntax for them without working with (ugh) a source filter. And some of
> these new syntaxes in the "core" language will actually be in standard
> modules, if they're not commonly used. Just like traits.

This is good. This is what I like to hear. This is why the answer to
all these stupid syntax questions should be "Look, if you need it, just put it
in a module when we're done. But can we please get on with getting Perl 6
designed and out the door, now?"

But it isn't, and I don't know why it isn't, and so we end up spending loads
of time discussing things that can be punted out to modules. Designing Perl 6
is hard enough; let's not try to fill CP6AN at the same time.

> I'll also point out that FINISH isn't really extra syntax, just extra
> vocabulary.

It's extra special cases, which come to the same thing.

> > my $result = if ($a) { $a } else { $b };
>
> Ack! We have? It does make sense if we want to be able to implement
> C<if> as a regular sub... I guess. Yuck.

Yep, we did. Of course, the "nice" thing about it is that it allows

do_thing() if if ($a) { $b } else { $c };

> That's illegal anyway. Can't chain statement modifiers :-)

Bah, should be able to!

> But a close relative would be possible:
> push @moves: [$i, $j] unless for 0..6 { last if abs(@new[$_]-@new[$_+1]) > 3 }
>
> Yeah, how about no. :-)

That's the thing, see. By saying no, we're saying "control structures like
'if' will be able to return a value, but control structures not like 'if'
won't", and that means we need to remove at least three words from 'When syntax
or semantics change, it will always be a change for the better: for greater
consistency, for more intuitability, for extra Do-What-I-Meanness.'... ;)

--
Resist the urge to start typing; thinking is a worthwhile alternative.
-- Kernighan and Pike

Dan Sugalski

unread,
Nov 18, 2003, 10:37:15 AM11/18/03
to Simon Cozens, Luke Palmer, perl6-l...@perl.org
On Tue, 18 Nov 2003, Simon Cozens wrote:

> Luke Palmer:

> > That's illegal anyway. Can't chain statement modifiers :-)
>
> Bah, should be able to!

Will be able to.

Dan

--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk

Simon Cozens

unread,
Nov 18, 2003, 10:34:05 AM11/18/03
to perl6-l...@perl.org
d...@sidhe.org (Dan Sugalski) writes:
> > Luke Palmer:
> > > That's illegal anyway. Can't chain statement modifiers :-)
> Will be able to.

I thought as much; Perl 6 will only be finally finished when the biotech
is sufficiently advanced to massively clone Larry...

--
<quidity> Sometimes it's better not to pedant.

Austin Hastings

unread,
Nov 18, 2003, 10:48:55 AM11/18/03
to Luke Palmer, Language List

> -----Original Message-----
> From: Luke Palmer [mailto:fibo...@babylonia.flatirons.org]
> Sent: Tuesday, November 18, 2003 9:21 AM
> To: Language List
> Subject: Control flow variables
>
>
> I was reading the most recent article on perl.com, and a code segment
> reminded me of something I see rather often in code that I don't like.
> Here's the code, Perl6ized:
>
> ... ;
> my $is_ok = 1;
> for 0..6 -> $t {
> if abs(@new[$t] - @new[$t+1]) > 3 {
> $is_ok = 0;
> last;
> }
> }
> if $is_ok {
> push @moves: [$i, $j];
> }
> ...

This is what I was talking about when I mentioned being able to do:

&cleanup .= { push @moves: [$i, $j]; }

a few weeks ago. Treat code vars like code, not like sub-refs.

=Austin

Luke Palmer

unread,
Nov 18, 2003, 10:49:00 AM11/18/03
to Austin Hastings, Language List
Austin Hastings writes:

> Luke Palmer wrote:
> > I was reading the most recent article on perl.com, and a code segment
> > reminded me of something I see rather often in code that I don't like.
> > Here's the code, Perl6ized:
> >
> > ... ;
> > my $is_ok = 1;
> > for 0..6 -> $t {
> > if abs(@new[$t] - @new[$t+1]) > 3 {
> > $is_ok = 0;
> > last;
> > }
> > }
> > if $is_ok {
> > push @moves: [$i, $j];
> > }
> > ...
>
> This is what I was talking about when I mentioned being able to do:
>
> &cleanup .= { push @moves: [$i, $j]; }
>
> a few weeks ago. Treat code vars like code, not like sub-refs.

I'm not sure I know what you mean with regard to this example.
Exemplify further, please?

Luke

> =Austin
>

Dan Sugalski

unread,
Nov 18, 2003, 11:01:59 AM11/18/03
to perl6-l...@perl.org
On Tue, 18 Nov 2003, Simon Cozens wrote:

> d...@sidhe.org (Dan Sugalski) writes:
> > > Luke Palmer:
> > > > That's illegal anyway. Can't chain statement modifiers :-)
> > Will be able to.
>
> I thought as much; Perl 6 will only be finally finished when the biotech
> is sufficiently advanced to massively clone Larry...

Not because of this. It's easier to allow it than not allow it.

Simon Cozens

unread,
Nov 18, 2003, 11:04:39 AM11/18/03
to perl6-l...@perl.org
Austin_...@Yahoo.com (Austin Hastings) writes:
> This is what I was talking about when I mentioned being able to do:
> &cleanup .= { push @moves: [$i, $j]; }

This reminds me of something I thought the other day might be useful:

$cleanup = bless {}, class {
method DESTROY { ... }
};

Of course, it probably wouldn't work in this context because you couldn't
guarantee that the destructor will be called at the point of loop exit, but I
like the anonymous class syntax anyway.

--
I've looked at the listing, and it's right!
-- Joel Halpern

Dan Sugalski

unread,
Nov 18, 2003, 11:14:54 AM11/18/03
to Simon Cozens, perl6-l...@perl.org
On Tue, 18 Nov 2003, Simon Cozens wrote:

> Austin_...@Yahoo.com (Austin Hastings) writes:
> > This is what I was talking about when I mentioned being able to do:
> > &cleanup .= { push @moves: [$i, $j]; }
>
> This reminds me of something I thought the other day might be useful:
>
> $cleanup = bless {}, class {
> method DESTROY { ... }
> };
>
> Of course, it probably wouldn't work in this context because you couldn't
> guarantee that the destructor will be called at the point of loop exit, but I
> like the anonymous class syntax anyway.

$cleanup = bless {}, class : impatient {
method DESTROY { ... }
};

That'll probably do it, at the expense of extra runtime block exit
overhead until the object dies. If you just want a block exit action,
then:

add_block_exit_action(\&foo);

or something similar will do it. (Though we could add new syntax for it if
you really want... :-)

Austin Hastings

unread,
Nov 18, 2003, 11:48:52 AM11/18/03
to Language List

> -----Original Message-----
> From: Luke Palmer [mailto:fibo...@babylonia.flatirons.org]

Quoting Luke Palmer from weeks back:

> From: Luke Palmer [mailto:fibo...@babylonia.flatirons.org]

> Jeff Clites writes:
> > Austin Hastings 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 <C>&block .= { more_stuff(); };</C> 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

Which begs the question of whether there's a way to get a handle to the current <C>for</C> loop from within?

LOOP: for 0..6 -> $t {


if abs(@new[$t] - @new[$t+1]) > 3 {

wrap &Block(): { call; handle_error(); };
last;
}
}

# handle_error() called here?

(Yes, this would presume that the <C>call</C> came first, since how could it interpolate the call otherwise. It's a limitation of the wrap-as-append philosophy.)

=Austin

Mark A. Biggar

unread,
Nov 18, 2003, 1:26:41 PM11/18/03
to perl6-l...@perl.org, Luke Palmer
Luke Palmer wrote:

> I was reading the most recent article on perl.com, and a code segment
> reminded me of something I see rather often in code that I don't like.
> Here's the code, Perl6ized:
>
> ... ;
> my $is_ok = 1;
> for 0..6 -> $t {
> if abs(@new[$t] - @new[$t+1]) > 3 {
> $is_ok = 0;
> last;
> }
> }
> if $is_ok {
> push @moves: [$i, $j];
> }
> ...

What's wrong with:

for 0..6 -> $t {
if abs(@new[$t] - @new[$t+1]) > 3 {

push @moves: [$i, $j];
last;
}
}

>
> I see this idiom a lot in code. You loop through some values on a
> condition, and do something only if the condition was never true.
> $is_ok is a control flow variable, something I like to minimize. Now,
> there are other ways to do this:
>
> if (0..6 ==> grep -> $t { abs(@new[$t] - @new[$t+1]) })
> { ... }
>
> But one would say that's not the cleanest thing in the world.

and very unreadable, (even if that's heresy :-) )

> Python pulled this idiom out in to the syntax (yay them), with C<else>
> on loops. The else block on a python loop executes only if you never
> broke out of the loop. That's a great idea.
>
> So, in Perl's postmodern tradition, I think we should steal that idea.
> I'm a little uneasy about calling it C<else>, though. Maybe C<FINISH>
> would do, making the example:
>
> for 0..6 -> $t {
> if abs(@new[$t] - @new[$t+1]) > 3 {
> last;
> }
> FINISH {
> push @moves: [$i, $j];
> }
> }

Violates least surprise, if the 'if' is true for '$t == 6' due
to the ambiguity between 'last' on '$t==6' and falling out the bottom
of the loop. Maybe you want FINISH_EARLY instead?

--
ma...@biggar.org
mark.a...@comcast.net

Mark A. Biggar

unread,
Nov 18, 2003, 1:31:51 PM11/18/03
to perl6-l...@perl.org, Luke Palmer
OOPS, totally miss-read your code, ignore my first part of my last
message.

--
ma...@biggar.org
mark.a...@comcast.net

Michael Lazzaro

unread,
Nov 18, 2003, 2:05:57 PM11/18/03
to perl6-l...@perl.org

On Tuesday, November 18, 2003, at 06:38 AM, Simon Cozens wrote:
> Given that we've introduced the concept of "if" having a return status:
>
> my $result = if ($a) { $a } else { $b };
>

Would that then imply that

sub blah {
... # 1
return if $a; # 2
... # 3
}

...would return $a if $a was true, and fall through to (3) if it was
false?


> d...@sidhe.org (Dan Sugalski) writes:
>>> Luke Palmer:
>>>> That's illegal anyway. Can't chain statement modifiers :-)
>> Will be able to.

I was under the strong impression that Larry had decided that syntactic
ambiguities prevented this from happening. (Now, of course, you will
ask me for a cite to the thread, which I can't even begin to find at
this point...)

MikeL

Austin Hastings

unread,
Nov 18, 2003, 3:04:08 PM11/18/03
to Michael Lazzaro, perl6-l...@perl.org

> -----Original Message-----
> From: Michael Lazzaro [mailto:mlaz...@cognitivity.com]
> Sent: Tuesday, November 18, 2003 2:06 PM
> To: perl6-l...@perl.org
> Subject: Re: Control flow variables
>
>
>

> On Tuesday, November 18, 2003, at 06:38 AM, Simon Cozens wrote:
> > Given that we've introduced the concept of "if" having a return status:
> >
> > my $result = if ($a) { $a } else { $b };
> >
>
> Would that then imply that
>
> sub blah {
> ... # 1
> return if $a; # 2
> ... # 3
> }
>
> ...would return $a if $a was true, and fall through to (3) if it was
> false?
>

It sure should, provided there were a correct context waiting, which would
quite nicely address another WIBNI thread a couple of months back about a
quick return under those conditions.

Very nice.

=Austin

Luke Palmer

unread,
Nov 18, 2003, 3:11:20 PM11/18/03
to Austin Hastings, Michael Lazzaro, perl6-l...@perl.org

I.... don't think so. I say that all the time to mean precisely:

if $a { return }

And I don't think people are ready to give that up.

In particular, if we kept our bottom-up parser around, this particular
construct would cause an infinite-lookahead problem. So for ambiguity's
sake, C<if $a> should not be a valid term without a block following.

Luke

Luke Palmer

unread,
Nov 18, 2003, 3:15:26 PM11/18/03
to Austin Hastings, Michael Lazzaro, perl6-l...@perl.org
Austin Hastings writes:
>
>
> > -----Original Message-----
> > From: Michael Lazzaro [mailto:mlaz...@cognitivity.com]
> > Sent: Tuesday, November 18, 2003 2:06 PM
> > To: perl6-l...@perl.org
> > Subject: Re: Control flow variables
> >
> >
> >
> > On Tuesday, November 18, 2003, at 06:38 AM, Simon Cozens wrote:
> > > Given that we've introduced the concept of "if" having a return status:
> > >
> > > my $result = if ($a) { $a } else { $b };
> > >
> >
> > Would that then imply that
> >
> > sub blah {
> > ... # 1
> > return if $a; # 2
> > ... # 3
> > }
> >
> > ...would return $a if $a was true, and fall through to (3) if it was
> > false?
> >
>
> It sure should, provided there were a correct context waiting, which would
> quite nicely address another WIBNI thread a couple of months back about a
> quick return under those conditions.

Oh, and if you really want to do that return thing without using a
C<given>, you can just:

sub blah {
return $a || goto CONT;
CONT:
...
}

I don't see what's wrong with that. :-p

Luke

Michael Lazzaro

unread,
Nov 18, 2003, 3:25:48 PM11/18/03
to perl6-l...@perl.org

>>> Would that then imply that
>>>
>>> sub blah {
>>> ... # 1
>>> return if $a; # 2
>>> ... # 3
>>> }
>>>
>>> ...would return $a if $a was true, and fall through to (3) if it was
>>> false?
>>>
>>
>> It sure should, provided there were a correct context waiting, which
>> would
>> quite nicely address another WIBNI thread a couple of months back
>> about a
>> quick return under those conditions.
>
> I.... don't think so. I say that all the time to mean precisely:
>
> if $a { return }
>
> And I don't think people are ready to give that up.
>
> In particular, if we kept our bottom-up parser around, this particular
> construct would cause an infinite-lookahead problem. So for
> ambiguity's
> sake, C<if $a> should not be a valid term without a block following.

So, just to make sure, these two lines are both valid, but do
completely different things:

return if $a;
return if $a { $a }


MikeL

Damian Conway

unread,
Nov 18, 2003, 4:01:40 PM11/18/03
to Language List
Luke Palmer started a discussion:


> I see this idiom a lot in code. You loop through some values on a
> condition, and do something only if the condition was never true.
> $is_ok is a control flow variable, something I like to minimize. Now,
> there are other ways to do this:
>
> if (0..6 ==> grep -> $t { abs(@new[$t] - @new[$t+1]) })
> { ... }
>
> But one would say that's not the cleanest thing in the world.

Only because you overdid the sugar. :

if grep {abs(@new[$^t] - @new[$^t+1]) > 3} 0..6
{ ... }

is pretty clean.

But, in any case, handling exceptional cases are what exceptions are for:

try {
for 0..6 -> $t {
die if abs(@new[$t] - @new[$t+1]) > 3;
}
CATCH {
push @moves: [$i, $j];
}
}

As regards return values of control structures, I had always assumed that:

* scalar control structures like C<if>, C<unless>, and C<given> return
the value of the last statement in their block that they evaluated;

* vector control structures like C<loop>, C<while>, and C<for> in a list
context return a list of the values of the last statement each
iteration evaluated;

* vector control structures like C<loop>, C<while>, and C<for> in a scalar
context return an integer indicating the number of times their block
was iterated.

So we might also write:

for 0..6 -> $t {
last if abs(@new[$t] - @new[$t+1]) > 3;
}
< 7 and push @moves: [$i, $j];


Damian


Damian Conway

unread,
Nov 18, 2003, 4:08:49 PM11/18/03
to Michael Lazzaro, perl6-l...@perl.org
Michael Lazzaro wrote:

> So, just to make sure, these two lines are both valid, but do completely
> different things:
>
> return if $a;

Means:

if ($a) { return }


> return if $a { $a }

Means:

if ($a) { return $a } else { return undef }


Damian

Luke Palmer

unread,
Nov 18, 2003, 4:22:37 PM11/18/03
to Damian Conway, Language List
Damian Conway writes:
> Luke Palmer started a discussion:
>
>
> >I see this idiom a lot in code. You loop through some values on a
> >condition, and do something only if the condition was never true.
> >$is_ok is a control flow variable, something I like to minimize. Now,
> >there are other ways to do this:
> >
> > if (0..6 ==> grep -> $t { abs(@new[$t] - @new[$t+1]) })
> > { ... }
> >
> >But one would say that's not the cleanest thing in the world.
>
> Only because you overdid the sugar. :
>
> if grep {abs(@new[$^t] - @new[$^t+1]) > 3} 0..6
> { ... }
>
> is pretty clean.

Right, but I messed it up, which isn't that important until later:

unless grep {abs(@new[$^t] - @new[$^t+1]) > 3} 0..6
{ ... }

Yeah, it is cleaner (I really like to put the list up in the front seat,
but in this case it doesn't help), but it's not really *clearer*, IMO.
Still a bit too "poetic" to read easily, IMO.

> But, in any case, handling exceptional cases are what exceptions are for:
>
> try {
> for 0..6 -> $t {
> die if abs(@new[$t] - @new[$t+1]) > 3;
> }
> CATCH {
> push @moves: [$i, $j];
> }
> }

And that's exactly equivalent to:

for 0..6 -> $t {
if abs(@new[$t] - @new[$t+1]) > 3 {
push @moves: [$i, $j];
last;
}
}

Which also eliminates the control variable. My C<if>/C<unless> typo may
have misled you, but the original example pushed only if *none* of them
passed the condition.

[snip]


> So we might also write:
>
> for 0..6 -> $t {
> last if abs(@new[$t] - @new[$t+1]) > 3;
> }
> < 7 and push @moves: [$i, $j];

Providing the semicolon rule doesn't bite us in the curly brace.

Hmm, you inspired a fine ambiguity:

if $something {
...
}
< 7 and $foo > if $something_else { ... }

Maybe control structures shouldn't return values after all :-p

(I honestly don't know what I have against that, other than fear that
someone might actually use it)

Luke

Austin Hastings

unread,
Nov 18, 2003, 4:30:24 PM11/18/03
to Language List

> -----Original Message-----
> From: Damian Conway [mailto:dam...@conway.org]
> Sent: Tuesday, November 18, 2003 4:02 PM
> To: Language List
> Subject: Re: Control flow variables
>
>

This seems excessive, but easily discarded during optimization. On the other
hand, I don't trust the "last statement evaluated" behavior for loops, since
the optimizer could very well do surprising things to loop statements.
(Likewise, however, for scalar control structures.)

What does this say about order of evaluation?

if @arry.length != while @arry { transmit(@arry.pop) or last; }
{
print "Couldn't send them all.";
}

I'm pretty sure that has to have unspecified behavior, but ... comment?

>
> So we might also write:
>
> for 0..6 -> $t {
> last if abs(@new[$t] - @new[$t+1]) > 3;
> }
> < 7 and push @moves: [$i, $j];
>
>
> Damian

Oh goody. Another (ab)use for named blocks:

my &named_block = for 0..6 -> $t { last if abs (@new[$t] - @new[$t+1]) >
3; }

push @moves: [$i, $j] if &named_block() < 7;

This seems hideously powerful, but at the same time dangerous. Kind of like
select.

=Austin

Austin Hastings

unread,
Nov 18, 2003, 4:30:28 PM11/18/03
to Luke Palmer, perl6-l...@perl.org

> -----Original Message-----
> From: Luke Palmer [mailto:fibo...@babylonia.flatirons.org]

How on earth are you going to have an infinite lookahead problem when a semicolon is the next character?

=Austin

Luke Palmer

unread,
Nov 18, 2003, 4:29:49 PM11/18/03
to Austin Hastings, perl6-l...@perl.org
Austin Hastings writes:
> > From: Luke Palmer [mailto:fibo...@babylonia.flatirons.org]
> >
> > Austin Hastings writes:
> > > > From: Michael Lazzaro [mailto:mlaz...@cognitivity.com]
> > > >
> > > > Would that then imply that
> > > >
> > > > sub blah {
> > > > ... # 1
> > > > return if $a; # 2
> > > > ... # 3
> > > > }
> > > >
> > > > ...would return $a if $a was true, and fall through to (3) if it was
> > > > false?
> > > >
> > >
> > In particular, if we kept our bottom-up parser around, this particular
> > construct would cause an infinite-lookahead problem. So for ambiguity's
> > sake, C<if $a> should not be a valid term without a block following.
> >
>
> How on earth are you going to have an infinite lookahead problem when a semicolon is the next character?

Sorry, s/\$a/some-hideously-long-condition/

Luke

> =Austin
>

Dan Sugalski

unread,
Nov 18, 2003, 4:34:25 PM11/18/03
to Language List
On Tue, 18 Nov 2003, Austin Hastings wrote:

> This seems excessive, but easily discarded during optimization. On the other
> hand, I don't trust the "last statement evaluated" behavior for loops, since
> the optimizer could very well do surprising things to loop statements.
> (Likewise, however, for scalar control structures.)

This shouldn't be a problem. If there's potential ambiguity then the
optimization can't be applied. Modulo optimizer bugs you'll be fine.

Damian Conway

unread,
Nov 18, 2003, 4:43:32 PM11/18/03
to perl6-l...@perl.org
Luke Palmer wrote:

> My C<if>/C<unless> typo may
> have misled you, but the original example pushed only if *none* of them
> passed the condition.

Ah, sorry, I misunderstood.

So you want:

push @moves, [$i, $j];


for 0..6 -> $t {
if abs(@new[$t] - @new[$t+1]) > 3 {

pop @moves;
last;
}
}

;-)

Damian

Austin Hastings

unread,
Nov 18, 2003, 5:00:37 PM11/18/03
to Dan Sugalski, Language List

> -----Original Message-----
> From: Dan Sugalski [mailto:d...@sidhe.org]
> Sent: Tuesday, November 18, 2003 4:34 PM
> To: Language List

> Subject: RE: Control flow variables
>
>
> On Tue, 18 Nov 2003, Austin Hastings wrote:
>
> > This seems excessive, but easily discarded during optimization.
> On the other
> > hand, I don't trust the "last statement evaluated" behavior for
> loops, since
> > the optimizer could very well do surprising things to loop statements.
> > (Likewise, however, for scalar control structures.)
>
> This shouldn't be a problem. If there's potential ambiguity then the
> optimization can't be applied. Modulo optimizer bugs you'll be fine.
>

That's the problem I have with it. I'm inclined to believe that the
optimization is more important than the postcondition, most of the time.

On the gripping hand, I *really* like "Damian's Simple Rules for Control
Flow Return Values". So much so that I can easily see a bunch of idioms
coming up around them.

First:

return if (some hideously long and possibly expensive guard);

That one just rocks. It's like:

$_ = &expensive();
return if;

<Singing Frank Zappa>
Valley Perl .. It's .. Valley Perl
like .. return if
when...ever
duh!
</>

Second:

I'm way not sure about how the vector context result of iteration structures
will work. Specifically, what happens when a loop forks a thread, or passes
to a parallelized coroutine? There may not actually BE a result. (Of course,
in a right-thinking system this will be noted, and replaced by a placeholder
object that will "wait" for the result if evaluated.)

Third:

The scalar count of iterations will make it seem that C<for> is a
macrification of C<map>, which isn't necessarily bad. In fact, I can see
this:

$count = for 0..@a -> $a {
check($a) or last;
}

if ($count != @a) { fail; }

Leading to:

if (scalar(@a) != for 0..@a -> $a { check($a) or last; }) { fail; }

Which leads to C<map>/C<grep> pretty directly:

if grep {!check($^a) } @a { fail; }

So it should actually help with the newbie learning curve, providing an easy
transition from loops to map/grep.

Which really is a good thing.

=Austin

Dan Sugalski

unread,
Nov 18, 2003, 5:03:28 PM11/18/03
to Austin Hastings, Language List
On Tue, 18 Nov 2003, Austin Hastings wrote:

>
>
> > -----Original Message-----
> > From: Dan Sugalski [mailto:d...@sidhe.org]
> > Sent: Tuesday, November 18, 2003 4:34 PM
> > To: Language List
> > Subject: RE: Control flow variables
> >
> >
> > On Tue, 18 Nov 2003, Austin Hastings wrote:
> >
> > > This seems excessive, but easily discarded during optimization.
> > On the other
> > > hand, I don't trust the "last statement evaluated" behavior for
> > loops, since
> > > the optimizer could very well do surprising things to loop statements.
> > > (Likewise, however, for scalar control structures.)
> >
> > This shouldn't be a problem. If there's potential ambiguity then the
> > optimization can't be applied. Modulo optimizer bugs you'll be fine.
> >
>
> That's the problem I have with it. I'm inclined to believe that the
> optimization is more important than the postcondition, most of the time.

Then don't do the things that would disable the optimization. It's
reasonably straightforward to tell whether a block's value may be used--if
there's any following statement then, well, it isn't.

Seiler Thomas

unread,
Nov 18, 2003, 5:37:22 PM11/18/03
to perl6-l...@perl.org
Damian Conway wrote:

> push @moves, [$i, $j];
> for 0..6 -> $t {
> if abs(@new[$t] - @new[$t+1]) > 3 {
> pop @moves;
> last;
> }
> }
>
>

Indeed, an elegant way around the problem.
So... lets call a function instead:

my $is_ok = 1;


for 0..6 -> $t {
if abs(@new[$t] - @new[$t+1]) > 3 {

$is_ok = 0;
last;
}
}
if $is_ok {

yada() # has sideeffects...
}

(wrote many such constructs for cgi sanity
checks and always found it mildly annoying)

regards
thomas

--
Imagination is more important than knowledge [Einstein]

wink.gif

Damian Conway

unread,
Nov 18, 2003, 5:55:13 PM11/18/03
to perl6-l...@perl.org
Seiler Thomas wrote:

> So... lets call a function instead:
>
> my $is_ok = 1;
> for 0..6 -> $t {
> if abs(@new[$t] - @new[$t+1]) > 3 {
> $is_ok = 0;
> last;
> }
> }
> if $is_ok {
> yada() # has sideeffects...
> }


That's just:

for 0..6, 'ok' -> $t {
when 'ok' { yada() }
last if abs(@new[$t] - @new[$t+1]) > 3;
}

;-)

Damian

David Wheeler

unread,
Nov 18, 2003, 9:35:58 PM11/18/03
to Joseph Ryan, Damian Conway, perl6-l...@perl.org
On Tuesday, November 18, 2003, at 06:11 PM, Joseph Ryan wrote:

> Not to be a jerk, but how about:
>
> my $is_ok = 1;
> for @array_of_random_values_and_types -> $t {
> if not some_sort_of_test($t) {


> $is_ok = 0;
> last;
> }
> }
> if $is_ok {
> yada() # has sideeffects...
> }

Isn't that just:

for @array_of_random_values_and_types, 'ok' -> $t {
when 'ok' { yada(); last }
last unless some_sort_of_test($t);
}

IOW, the topic is only 'ok' when all of the items in the array have
been processed, which in your code is what happens when
some_sort_of_test($t) returns a true value.

Regards,

David

--
David Wheeler AIM: dwTheory
da...@kineticode.com ICQ: 15726394
http://www.kineticode.com/ Yahoo!: dew7e
Jabber: The...@jabber.org
Kineticode. Setting knowledge in motion.[sm]

Damian Conway

unread,
Nov 18, 2003, 9:26:09 PM11/18/03
to Joseph Ryan, perl6-l...@perl.org
Joseph Ryan wrote:

> Not to be a jerk, but how about:
>

> my $is_ok = 1;


> for @array_of_random_values_and_types -> $t {
> if not some_sort_of_test($t) {

> $is_ok = 0;
> last;
> }
> }
> if $is_ok {
> yada() # has sideeffects...
> }

That's just:

given @array_of_random_values_and_types -> @data {
for @data.kv, +@data -> $i, $t {
when +@data { yada() }
last if not some_sort_of_test($t);
}
}


;-)

Damian

Joseph Ryan

unread,
Nov 18, 2003, 9:44:03 PM11/18/03
to David Wheeler, perl6-l...@perl.org
David Wheeler wrote:

> On Tuesday, November 18, 2003, at 06:11 PM, Joseph Ryan wrote:
>
>> Not to be a jerk, but how about:
>>
>> my $is_ok = 1;
>> for @array_of_random_values_and_types -> $t {
>> if not some_sort_of_test($t) {
>> $is_ok = 0;
>> last;
>> }
>> }
>> if $is_ok {
>> yada() # has sideeffects...
>> }
>
>
> Isn't that just:
>
> for @array_of_random_values_and_types, 'ok' -> $t {
> when 'ok' { yada(); last }
> last unless some_sort_of_test($t);
> }
>
> IOW, the topic is only 'ok' when all of the items in the array have
> been processed, which in your code is what happens when
> some_sort_of_test($t) returns a true value.


And also if @array_of_random_values contains 'ok'.

- Joe

Joseph Ryan

unread,
Nov 18, 2003, 9:11:33 PM11/18/03
to Damian Conway, perl6-l...@perl.org
Damian Conway wrote:

Not to be a jerk, but how about:

my $is_ok = 1;


for @array_of_random_values_and_types -> $t {
if not some_sort_of_test($t) {

$is_ok = 0;
last;
}
}
if $is_ok {
yada() # has sideeffects...
}

:)

- Joe

Damian Conway

unread,
Nov 18, 2003, 9:46:39 PM11/18/03
to perl6-l...@perl.org
David Wheeler wrote:

> Isn't that just:
>
> for @array_of_random_values_and_types, 'ok' -> $t {
> when 'ok' { yada(); last }
> last unless some_sort_of_test($t);
> }
>
> IOW, the topic is only 'ok' when all of the items in the array have been
> processed

Unless, of course, the string 'ok' is also one of the random_values_and_types.
Hence my alternative solution.

Damian

David Wheeler

unread,
Nov 18, 2003, 9:49:31 PM11/18/03
to Joseph Ryan, perl6-l...@perl.org
On Tuesday, November 18, 2003, at 06:44 PM, Joseph Ryan wrote:

> And also if @array_of_random_values contains 'ok'.

D'oh! See Damian's solution, then. ;-)

Larry Wall

unread,
Nov 19, 2003, 12:36:31 AM11/19/03
to perl6-l...@perl.org
On Tue, Nov 18, 2003 at 11:14:54AM -0500, Dan Sugalski wrote:
: On Tue, 18 Nov 2003, Simon Cozens wrote:
:
: > Austin_...@Yahoo.com (Austin Hastings) writes:
: > > This is what I was talking about when I mentioned being able to do:
: > > &cleanup .= { push @moves: [$i, $j]; }
: >
: > This reminds me of something I thought the other day might be useful:
: >
: > $cleanup = bless {}, class {
: > method DESTROY { ... }
: > };
: >
: > Of course, it probably wouldn't work in this context because you couldn't
: > guarantee that the destructor will be called at the point of loop exit, but I
: > like the anonymous class syntax anyway.
:
: $cleanup = bless {}, class : impatient {
: method DESTROY { ... }
: };
:
: That'll probably do it, at the expense of extra runtime block exit
: overhead until the object dies. If you just want a block exit action,
: then:
:
: add_block_exit_action(\&foo);
:
: or something similar will do it. (Though we could add new syntax for it if
: you really want... :-)

Why are you guys dragging all this Perl 5 syntax back into Perl 6?
There is no bless function in Perl 6--it's a method. Class traits
are introduced with "is", not ":". And you don't need to backwhack
the &foo.

Sheesh.

Oh, by the way, if you want to return a value from a control structure,
you will have to do so explicitly by putting "do {...}" around it.
We will certainly *not* allow both of these:

return if $a;
return if $a {...};

Shudder. That is so unreadable. It doesn't even work in English.

And nested modifiers are still quite illegal in Standard Perl 6.

As for the original question that started this whole silly thread,
control structures that return values should probably be considered
some kind of generator, and have an explicit "yield"-like statement
that is orthogonal to "last" and such. Such a generator would be
explicitly marked, as with "do {...}" above, only different. The
inside of such a generator after the loop is the natural place
to say what happens if nothing in the loop "works".

It's important with unusual control structures to say what you mean
up front. Making the reader back up and reparse is antisocial.
Which is why we allow statement modifiers only in moderation.

Larry

Piers Cawley

unread,
Nov 19, 2003, 4:15:01 AM11/19/03
to Damian Conway, perl6-l...@perl.org
Damian Conway <dam...@conway.org> writes:

Or:

my $guard = Object.new;
for @array_of_random_values_and_types, $guard
-> { when $guard { yada(); last }
last unless some_sort_of_test($_) }

If there's some danger of some weird equality thing somehow causing a
problem there, you might need to make a Guard class with a very strict
'=~' implementation, but otherwise I can't see any problem.

Of course, that's better if some_sort_of_test is actually a method,
because then it becomes:

my $guard = class { method some_sort_of_test { yada() }}.new;

for *@array_of_random_values_and_types, $guard
-> { last unless .some_sort_of_test }

All of which means you can wrap it up in a macro and prove Simon's
point about what's syntax and what's CP6AN:

macro unless_all( Block &test is parsed /<perl.expression>/,
Block &consequence, *@ary )
{ my $guard = Object.new;
for *@ary, $guard
-> { when $guard { &consequence() ; last }
when &test { last } } }

But I've probably got the signature slightly wrong.

Higher Order Functions/Methods/Macros are great aren't they?


Jonathan Scott Duff

unread,
Nov 18, 2003, 2:15:42 PM11/18/03
to Michael Lazzaro, perl6-l...@perl.org
On Tue, Nov 18, 2003 at 11:05:57AM -0800, Michael Lazzaro wrote:
>
> On Tuesday, November 18, 2003, at 06:38 AM, Simon Cozens wrote:
> >Given that we've introduced the concept of "if" having a return status:
> >
> > my $result = if ($a) { $a } else { $b };
> >
>
> Would that then imply that
>
> sub blah {
> ... # 1
> return if $a; # 2
> ... # 3
> }
>
> ...would return $a if $a was true,

That makes no sense. Besides in the above fantasy, the result of the
"if" is the last thing evaluated in the block. In this case, the
block is a single "return" statement. Perhaps it would be clearer
thusly:

my $result = if ($a) { $b } else { $c }; # Same as ...
my $result = ($a) ?? $b :: $c; # ?

> and fall through to (3) if it was
> false?

Of course, that's how it works :)

-Scott
--
Jonathan Scott Duff
du...@lighthouse.tamucc.edu

Gordon Henriksen

unread,
Nov 18, 2003, 2:14:59 PM11/18/03
to Michael Lazzaro, perl6-l...@perl.org
No, because the

if $a

from "return if $a;" doesn't match the production

if <expression> <block> [else <block>]

I so don't want to be anywhere near the Perl6 parser...

--

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
gor...@iclub.com


> -----Original Message-----
> From: Michael Lazzaro [mailto:mlaz...@cognitivity.com]

> Sent: Tuesday, November 18, 2003 2:06 PM
> To: perl6-l...@perl.org
> Subject: Re: Control flow variables
>
>
>

> On Tuesday, November 18, 2003, at 06:38 AM, Simon Cozens wrote:
> > Given that we've introduced the concept of "if" having a
> return status:
> >
> > my $result = if ($a) { $a } else { $b };
> >
>
> Would that then imply that
>
> sub blah {
> ... # 1
> return if $a; # 2
> ... # 3
> }
>

> ...would return $a if $a was true, and fall through to (3) if it was
> false?
>
>
> > d...@sidhe.org (Dan Sugalski) writes:
> >>> Luke Palmer:
> >>>> That's illegal anyway. Can't chain statement modifiers :-)
> >> Will be able to.
>
> I was under the strong impression that Larry had decided that
> syntactic
> ambiguities prevented this from happening. (Now, of course, you will
> ask me for a cite to the thread, which I can't even begin to find at
> this point...)
>
> MikeL
>
>


Smylers

unread,
Nov 18, 2003, 2:18:54 PM11/18/03
to perl6-l...@perl.org
Michael Lazzaro writes:

> d...@sidhe.org (Dan Sugalski) writes:
>
> > Luke Palmer:
> >
> > > That's illegal anyway. Can't chain statement modifiers :-)
> >
> > Will be able to.
>
> I was under the strong impression that Larry had decided that
> syntactic ambiguities prevented this from happening.

I also was under the strong impression that Larry had decreed that we
wouldn't have chained statement modifiers ... but I thought it was
because Larry had decided they would be a bad thing to have rather than
because they aren't feasible.

> (Now, of course, you will ask me for a cite to the thread, which I
> can't even begin to find at this point...)

Me neither. A Google Groups search on perl.perl6.language with the
author 'Larry' doesn't through up anything relevant for "statement
modifiers" or obvious variants.

Smylers

Jonathan Scott Duff

unread,
Nov 18, 2003, 5:59:24 PM11/18/03
to Seiler Thomas, perl6-l...@perl.org
On Tue, Nov 18, 2003 at 11:37:22PM +0100, Seiler Thomas wrote:
> So... lets call a function instead:
>
> my $is_ok = 1;
> for 0..6 -> $t {
> if abs(@new[$t] - @new[$t+1]) > 3 {
> $is_ok = 0;
> last;
> }
> }
> if $is_ok {
> yada() # has sideeffects...
> }

my $t = 0..6;
yada() if none(abs(@new[$t] ^- @new[$t+1])) > 3;

:-P

Gordon Henriksen

unread,
Nov 18, 2003, 6:28:59 PM11/18/03
to Austin_...@yahoo.com, perl6-l...@perl.org
Austin Hastings wrote:

> I'm way not sure about how the vector context result of iteration
structures
> will work. Specifically, what happens when a loop forks a thread, or
passes
> to a parallelized coroutine? There may not actually BE a result. (Of
course,
> in a right-thinking system this will be noted, and replaced by a
placeholder
> object that will "wait" for the result if evaluated.)

Whuh? Tangential at best... The result would be the same as in a
non-vectorized version, just repeated automatically for you.

my @b = for @a -> $_ {
...
}

Should be broadly equivalent to:

my @b = map { ... } @a;

- OR -

# (Apologies for the perl5-isms.)
for @a -> $_ {
push @b: do { ... };
}

If the non-vectorized version has hidden a thread join operation in a
tied or otherwise magical result value, then so too would the vectorized
version. But that's a completely orthogonal feature; unrelated and not
in conflict.

Gordon Henriksen

unread,
Nov 18, 2003, 6:38:19 PM11/18/03
to Seiler Thomas, perl6-l...@perl.org
> Damian Conway wrote:
>
> > push @moves, [$i, $j];
> > for 0..6 -> $t {
> > if abs(@new[$t] - @new[$t+1]) > 3 {
> > pop @moves;
> > last;
> > }
> > }


Thomas Seiler writes:

> my $is_ok = 1;
> for 0..6 -> $t {
> if abs(@new[$t] - @new[$t+1]) > 3 {
> $is_ok = 0;
> last;
> }
> }
> if $is_ok {
> yada() # has sideeffects...
> }


Ironically, this flow control problem was solved many years ago indeed,
and with considerable elegance. To wit:

my $is_ok = 1;
for 0..6 -> $t {
if abs(@new[$t] - @new[$t+1]) > 3 {

goto SKIP_YADA;
}
}

yada();
SKIP_YADA:

Yeah, so I'm a trouble-maker. Sorry: I don't consider downwards,
scope-escaping goto to be harmful.

Does this cause a bit less heartburn?

YADA: {


my $is_ok = 1;
for 0..6 -> $t {
if abs(@new[$t] - @new[$t+1]) > 3 {

break YADA;
}
}

yada();
}

Loop controls are just goto in disguise, anyhow.

Austin Hastings

unread,
Nov 19, 2003, 9:06:44 AM11/19/03
to Gordon Henriksen, perl6-l...@perl.org
> Austin Hastings wrote:
>
> > I'm way not sure about how the vector context result of iteration
> structures
> > will work. Specifically, what happens when a loop forks a thread, or
> passes
> > to a parallelized coroutine? There may not actually BE a result. (Of
> course,
> > in a right-thinking system this will be noted, and replaced by a
> placeholder
> > object that will "wait" for the result if evaluated.)
>
> Whuh? Tangential at best... The result would be the same as in a
> non-vectorized version, just repeated automatically for you.

Would EVENTUALLY be the same as ...

Sure. The whole iterator/generator thing has already been covered, so I'm
pretty sure we've got the underpinnings.

> my @b = for @a -> $_ {
> ...
> }
>
> Should be broadly equivalent to:
>
> my @b = map { ... } @a;
>
> - OR -
>
> # (Apologies for the perl5-isms.)
> for @a -> $_ {
> push @b: do { ... };
> }

Yes. I think I made that point lower down. In fact, the "collector" behavior
of evaluating for in a vector context should help people transition from
C<for> to C<map>. (Only Satan, or his handpicked successor Damian, will help
them get from there to C<any>/C<none>, however. :-)


> If the non-vectorized version has hidden a thread join operation in a
> tied or otherwise magical result value, then so too would the vectorized
> version. But that's a completely orthogonal feature; unrelated and not
> in conflict.

True, but of course the scalar version doesn't have to wait for the results.

=Austin

Randal L. Schwartz

unread,
Nov 19, 2003, 9:45:30 AM11/19/03
to perl6-l...@perl.org
>>>>> "Smylers" == Smylers <Smy...@stripey.com> writes:

Smylers> I also was under the strong impression that Larry had decreed
Smylers> that we wouldn't have chained statement modifiers ... but I
Smylers> thought it was because Larry had decided they would be a bad
Smylers> thing to have rather than because they aren't feasible.

They weren't chained in Perl5, very deliberately.

Larry added modifiers partially to get "do { } while $cond" to work,
and partially because he had used them in RSTS/E BASIC (which I've
also used, and recognized immediately). But when people started
nesting them, the code became incredibly unreadable quickly, so
no-nesting for Perl was a deliberate choice, not an implementation
detail.

Unless Larry has come up with an overwhelming reason to permit them
after years of not having them, I doubt we'd see that (IMHO mistake)
in Perl6.

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<mer...@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

Austin Hastings

unread,
Nov 19, 2003, 11:05:54 AM11/19/03
to Randal L. Schwartz, perl6-l...@perl.org

> -----Original Message-----
> From: Randal L. Schwartz [mailto:mer...@stonehenge.com]
> Sent: Wednesday, November 19, 2003 9:46 AM
> To: perl6-l...@perl.org
> Subject: Re: Control flow variables
>
>

> >>>>> "Smylers" == Smylers <Smy...@stripey.com> writes:
>
> Smylers> I also was under the strong impression that Larry had decreed
> Smylers> that we wouldn't have chained statement modifiers ... but I
> Smylers> thought it was because Larry had decided they would be a bad
> Smylers> thing to have rather than because they aren't feasible.
>
> They weren't chained in Perl5, very deliberately.
>
> Larry added modifiers partially to get "do { } while $cond" to work,
> and partially because he had used them in RSTS/E BASIC (which I've
> also used, and recognized immediately). But when people started
> nesting them, the code became incredibly unreadable quickly, so
> no-nesting for Perl was a deliberate choice, not an implementation
> detail.

This is surprising. Perl has never failed to provide me with an adequacy of
rope in other places. Why get squeamish in this instance?

> Unless Larry has come up with an overwhelming reason to permit them
> after years of not having them, I doubt we'd see that (IMHO mistake)
> in Perl6.

Hmm. While I don't really expect to see leap year code written using nested
modifiers, I think it would be nice to have each of them appear once:

print for @a if $debug;

=Austin

Randal L. Schwartz

unread,
Nov 19, 2003, 11:18:57 AM11/19/03
to Austin_...@yahoo.com, perl6-l...@perl.org
>>>>> "Randal" == Randal L Schwartz <mer...@stonehenge.com> writes:

Randal> I actually consider that an annoying statement. I have to back up
Randal> three times to figure out what it means.

And before someone whips out the Schwartzian Transform to undermine
my statement... please note that in Perl6, you'll be able to write
that left to right, which I consider a wonderful plus. :)

Randal L. Schwartz

unread,
Nov 19, 2003, 11:15:21 AM11/19/03
to Austin_...@yahoo.com, perl6-l...@perl.org
>>>>> "Austin" == Austin Hastings <Austin_...@Yahoo.com> writes:

Austin> This is surprising. Perl has never failed to provide me with
Austin> an adequacy of rope in other places. Why get squeamish in this
Austin> instance?

The rope in other places provides overwhelming positive benefits as
well, I gather. Everything is a tradeoff.

Austin> Hmm. While I don't really expect to see leap year code written
Austin> using nested modifiers, I think it would be nice to have each
Austin> of them appear once:

Austin> print for @a if $debug;

I actually consider that an annoying statement. I have to back up

three times to figure out what it means.

I think Larry was on the right track here.

Luke Palmer

unread,
Nov 19, 2003, 11:25:38 AM11/19/03
to Seiler Thomas, perl6-l...@perl.org
Jonathan Scott Duff writes:
> On Tue, Nov 18, 2003 at 11:37:22PM +0100, Seiler Thomas wrote:
> > So... lets call a function instead:
> >
> > my $is_ok = 1;
> > for 0..6 -> $t {
> > if abs(@new[$t] - @new[$t+1]) > 3 {
> > $is_ok = 0;
> > last;
> > }
> > }
> > if $is_ok {
> > yada() # has sideeffects...
> > }
>
> my $t = 0..6;
> yada() if none(abs(@new[$t] ^- @new[$t+1])) > 3;
>
> :-P

Ghod I love junctions. :-)

Luke

Luke Palmer

unread,
Nov 19, 2003, 11:30:15 AM11/19/03
to Piers Cawley, Damian Conway, perl6-l...@perl.org
Piers Cawley writes:
> All of which means you can wrap it up in a macro and prove Simon's
> point about what's syntax and what's CP6AN:
>
> macro unless_all( Block &test is parsed /<perl.expression>/,
> Block &consequence, *@ary )
> { my $guard = Object.new;
> for *@ary, $guard
> -> { when $guard { &consequence() ; last }
> when &test { last } } }
>
> But I've probably got the signature slightly wrong.

I think the only thing that's wrong with your signature is that you said
"macro" instead of "sub". Well, and &test has to be finessed into an
executable block somehow, but we're not supposed to know how yet.

> Higher Order Functions/Methods/Macros are great aren't they?

What a modern thinker! Use a *function* to do a common task? *What*
are you talking about!? :-)

Luke

Larry Wall

unread,
Nov 19, 2003, 1:19:06 PM11/19/03
to perl6-l...@perl.org
On Wed, Nov 19, 2003 at 08:08:49AM +1100, Damian Conway wrote:
: Michael Lazzaro wrote:
:
: >So, just to make sure, these two lines are both valid, but do completely
: >different things:
: >
: > return if $a;
:
: Means:
:
: if ($a) { return }
:
:
: > return if $a { $a }
:
: Means:
:
: if ($a) { return $a } else { return undef }

No, it's a syntax error. You must write

return do { if $a { $a } }

to mean that. At least in my version of Perl 6. AIFIYP.

Sentences are a basic concept in all human languages. I've decided
that it's a bad psychological mistake to overgeneralize phrase-level
syntax to encompass sentence-level syntax. The Perl 6 grammar
will know when it's starting to parse a statement, and will
make distinctions based on that. That implies that any sub/macro
definitions for "if" have to be overloaded on parser state somehow.
We could play "multi" tricks, but I suspect the right solution is
more on the order of how we differentiate prefix:+ from infix:+.
So perhaps statement level "if" is statement:if, while modifier "if"
is modifier:if. Huffman says those should be long anyway.

It may well be that there is a generalization to be made here, but
it's more on the order of foo:bar refers to some grammar rule
or set of rules named foo.

Also, since multi is orthogonal to naming, it'd be possible to define
things such that all variants of "if" and "while" look like this:

multi sub *statement:if (...
multi sub *modifier:if (...
multi sub *statement:while (...
multi sub *modifier:while (...

But that sort of generality would completely screw up the optimizer,
I expect, since multi is an inherently run-time concept. It would
also create a great deal of magical action at a distance. Lexically
scoped macros (or other grammatical mods) are a much better approach
to control structure variation. There might be some room for lexically
scoped multi subs defining control structure, but you'd still probably
take the optimizer hit.

Larry

Larry Wall

unread,
Nov 19, 2003, 1:53:56 PM11/19/03
to perl6-l...@perl.org
On Tue, Nov 18, 2003 at 06:28:59PM -0500, Gordon Henriksen wrote:
: Whuh? Tangential at best... The result would be the same as in a

: non-vectorized version, just repeated automatically for you.
:
: my @b = for @a -> $_ {
: ...
: }

That will be a syntax error. Generators are too mind-stretching to
inflict on novices as ordinary syntax. You'll have to say something
explicit like:

my @b = generate {
for @a -> $_ {
yield ...
}
}

It's vaguely possible that "generate" and "do" are the same thing.
It's quite possible that the best name is something else entirely.
But "for" ain't it...

: Should be broadly equivalent to:


:
: my @b = map { ... } @a;
:
: - OR -
:
: # (Apologies for the perl5-isms.)
: for @a -> $_ {
: push @b: do { ... };

: }

Hmm? I see no perl5-isms there. Or rather, I see no non-perl6-isms...

Larry

Larry Wall

unread,
Nov 19, 2003, 2:03:25 PM11/19/03
to perl6-l...@perl.org
On Wed, Nov 19, 2003 at 09:30:15AM -0700, Luke Palmer wrote:
: Piers Cawley writes:
: > All of which means you can wrap it up in a macro and prove Simon's
: > point about what's syntax and what's CP6AN:
: >
: > macro unless_all( Block &test is parsed /<perl.expression>/,
: > Block &consequence, *@ary )
: > { my $guard = Object.new;
: > for *@ary, $guard
: > -> { when $guard { &consequence() ; last }
: > when &test { last } } }
: >
: > But I've probably got the signature slightly wrong.

So far we've only allowed "is parsed" on the macro itself, not on
individual arguments. Still, that's an interesting idea.

: I think the only thing that's wrong with your signature is that you said


: "macro" instead of "sub". Well, and &test has to be finessed into an
: executable block somehow, but we're not supposed to know how yet.

Hmm, how about statement:unless_all and modifier:unless_all?

: > Higher Order Functions/Methods/Macros are great aren't they?

:
: What a modern thinker! Use a *function* to do a common task? *What*
: are you talking about!? :-)

Well, you mayn't put "is parsed" on a function. Macros have special
rules to enforce lexical scoping of syntax munging, since the syntax
must be known when the call is parsed. A function call can be parsed
without such special knowledge.

Larry

Jonathan Scott Duff

unread,
Nov 19, 2003, 10:12:01 AM11/19/03
to perl6-l...@perl.org
On Tue, Nov 18, 2003 at 09:36:31PM -0800, Larry Wall wrote:
> As for the original question that started this whole silly thread,
> control structures that return values should probably be considered
> some kind of generator, and have an explicit "yield"-like statement
> that is orthogonal to "last" and such. Such a generator would be
> explicitly marked, as with "do {...}" above, only different. The
> inside of such a generator after the loop is the natural place
> to say what happens if nothing in the loop "works".

I don't understand ... Do you mean something like this?

confer {
for @a -> $x { ... } || beget @results;
}

where "confer" is the do-like marker and "beget" is the yield-like
statement. But why not this?

for @a -> $x { ... } or do { ... }

I need an example.

thanks,

Gordon Henriksen

unread,
Nov 19, 2003, 2:49:40 PM11/19/03
to Larry Wall, perl6-l...@perl.org
Larry Wall wrote:

> On Tue, Nov 18, 2003 at 06:28:59PM -0500, Gordon Henriksen wrote:
>
> > my @b = for @a -> $_ {
> > ...
> > }
>
> That will be a syntax error. Generators are too mind-stretching to

> inflict on novices [...]

I making the point that within the context of this we-wish-loops-were-
expressions discussion, the "for expression" was simply another way
to spell map, at least when autoiterating an array.

I certainly wasn't thinking in terms of coroutines--they absolutely
deserve a large syntactic barrier.


> > # (Apologies for the perl5-isms.)
> > for @a -> $_ {
> > push @b: do { ... };
> > }
>
> Hmm? I see no perl5-isms there. Or rather, I see no
> non-perl6-isms...

It's been a while since I read Apocalypses; I wasn't sure if do { }
(still) meant what I meant it to mean ("the result of the last
statement in the block"). There was also a scalar() in there when I
wrote the apology, but I removed it on further consideration of the
equivalence to map {}. :)

Luke Palmer

unread,
Nov 19, 2003, 3:27:56 PM11/19/03
to Gordon Henriksen, Larry Wall, perl6-l...@perl.org
Gordon Henriksen writes:
> Larry Wall wrote:
>
> > On Tue, Nov 18, 2003 at 06:28:59PM -0500, Gordon Henriksen wrote:
> >
> > > my @b = for @a -> $_ {
> > > ...
> > > }
> >
> > That will be a syntax error. Generators are too mind-stretching to
> > inflict on novices [...]
>
> I making the point that within the context of this we-wish-loops-were-
> expressions discussion, the "for expression" was simply another way
> to spell map, at least when autoiterating an array.
>
> I certainly wasn't thinking in terms of coroutines--they absolutely
> deserve a large syntactic barrier.

I don't think generate{} and yield() were supposed to indicate
coroutines. Instead, it's more like Mathematica's Sow[] and Reap[],
which would work (Perl6-ized) as follows:

@a = reap {
sow 1;
some-other-statement;
sow 2;
} # @a is (1,2)

It's a nice concept; it simplifies certain kinds of list processing
greatly. It would easily be implemented with coroutines, which might
also explain the yield().

Luke

Larry Wall

unread,
Nov 19, 2003, 3:49:21 PM11/19/03
to perl6-l...@perl.org
On Wed, Nov 19, 2003 at 09:12:01AM -0600, Jonathan Scott Duff wrote:

Sorry, I wasn't being very clear. It wouldn't be logically attached to
the outside of the for, but to the inside of the "confer", or whatever:

@foo = gather {
for @a -> $x { pick $x if mumble($x) }
DEFAULT { @results }
}

In which case you could also write:

@foo = gather {
DEFAULT { @results }
for @a -> $x { pick $x if mumble($x) }
}

But it might be clearer to put it outside:

@foo = gather {
for @a -> $x { pick $x if mumble($x) }
} or @results;

On the other hand, putting the default up front is clearer if the
block is long. Could even be something like:

@foo = gather is default(@results) {
for @a -> $x { pick $x if mumble($x) }
}

Larry

Austin Hastings

unread,
Nov 19, 2003, 7:13:43 PM11/19/03
to Larry Wall, perl6-l...@perl.org
> -----Original Message-----
> From: Larry Wall [mailto:la...@wall.org]

> On the other hand, putting the default up front is clearer if the
> block is long. Could even be something like:
>
> @foo = gather is default(@results) {
> for @a -> $x { pick $x if mumble($x) }
> }

And C<gather> is a better name than C<grep>, overall.

What does C<scatter> do?

=Austin


Jonathan Lang

unread,
Nov 19, 2003, 11:37:49 PM11/19/03
to perl6-l...@perl.org
Larry Wall wrote:
> So far we've only allowed "is parsed" on the macro itself, not on
> individual arguments. Still, that's an interesting idea.

Forgive me if this has already been addressed, but this could have some
useful applications:

So far, everything I've read about macro parsing concentrates on parsing
the positional arguments; I haven't seen anything about how to go about
defining a custom parse rule for the list arguments. In particular, I'm
thinking about something along the lines of:

macro element(name, *@attribute is parsed /\s+/)
is parsed / \< /? (<QName>) \s* (.*?) /? \> /
{...}

where the "is parsed" trait of the list parameter defines a rule used to
split the string fed into it into a list of arguments.

I could see something similar being done for named parameters, but you'd
need to define both a "split" rule and a name-vs-value parse rule, and
you'd have to address if (and if so, how) a named parameter can be
inserted between positional and/or list parameters.

=====
Jonathan "Dataweaver" Lang

__________________________________
Do you Yahoo!?
Free Pop-Up Blocker - Get it now
http://companion.yahoo.com/

Luke Palmer

unread,
Nov 20, 2003, 3:00:04 AM11/20/03
to Jonathan Lang, perl6-l...@perl.org
Jonathan Lang writes:
> Larry Wall wrote:
> > So far we've only allowed "is parsed" on the macro itself, not on
> > individual arguments. Still, that's an interesting idea.
>
> Forgive me if this has already been addressed, but this could have some
> useful applications:
>
> So far, everything I've read about macro parsing concentrates on parsing
> the positional arguments; I haven't seen anything about how to go about
> defining a custom parse rule for the list arguments. In particular, I'm
> thinking about something along the lines of:
>
> macro element(name, *@attribute is parsed /\s+/)
> is parsed / \< /? (<QName>) \s* (.*?) /? \> /
> {...}
>
> where the "is parsed" trait of the list parameter defines a rule used to
> split the string fed into it into a list of arguments.

You can only "split" what is passed in as much as you can split a parse
tree. The best one can do here is grab text, split, and reparse each of
the segments. That's not hard to do manually, and I think it best be
done manually. There's only so much complexity you can pack into a
signature and still make it thinkable.

> I could see something similar being done for named parameters, but you'd
> need to define both a "split" rule and a name-vs-value parse rule, and
> you'd have to address if (and if so, how) a named parameter can be
> inserted between positional and/or list parameters.

Again, too much complexity for the payoff. Code it manually. (Which
might mean using a proxy sub to do the parsing, which forwards the call
along to the "content", so you can get Perl's semantics with your
syntax).

As much as I do like adding useful features to the language, I do think
we have to solve our own problems *sometimes*.

Luke

Smylers

unread,
Nov 19, 2003, 3:29:40 PM11/19/03
to perl6-l...@perl.org
Larry Wall writes:

> And nested modifiers are still quite illegal in Standard Perl 6.

Right.

Anybody else get the feeling we should write that down somewhere, so we
don't have to have this conversation again in a few months?

Smylers

Smylers

unread,
Nov 19, 2003, 3:28:15 PM11/19/03
to perl6-l...@perl.org
Larry Wall writes:

> On Wed, Nov 19, 2003 at 08:08:49AM +1100, Damian Conway wrote:
>
> : Michael Lazzaro wrote:
> :

> : > return if $a { $a }
> :
> : Means:
> :
> : if ($a) { return $a } else { return undef }
>
> No, it's a syntax error. You must write
>
> return do { if $a { $a } }
>
> to mean that. At least in my version of Perl 6. AIFIYP.

Excellent! Larry, thank you for being here and enforcing sanity!

The above scared me, so I'm most glad to hear it won't be in the
language. Apart from looking confusingly similar to much more common
statements, there already seem to be ample ways of doing this,
including:

return $a || undef;

or, more generally if actually the two C<$a>s are not the same:

return $a ?? $b :: undef;

Smylers

Jonathan Scott Duff

unread,
Nov 19, 2003, 4:14:10 PM11/19/03
to Larry Wall, Damian Conway, perl6-l...@perl.org
On Wed, Nov 19, 2003 at 12:49:21PM -0800, Larry Wall wrote:
> Sorry, I wasn't being very clear. It wouldn't be logically attached to
> the outside of the for, but to the inside of the "confer", or whatever:
>
> @foo = gather {
> for @a -> $x { pick $x if mumble($x) }
> DEFAULT { @results }
> }

So ... the only way to get Damians semantics ...

On Wed, Nov 19, 2003 at 08:01:40AM +1100, Damian Conway wrote:
> * vector control structures like C<loop>, C<while>, and C<for> in
> a list context return a list of the values of the last statement
> each iteration evaluated;
>
> * vector control structures like C<loop>, C<while>, and C<for> in
> a scalar context return an integer indicating the number of
> times their block was iterated.

... is to surround the control structure with a gather { ... } ??

It seems like "gather" or whatever should be some sort of modifier to
for/loop/while/until

@foo = for : gather @a -> $x { ... }
if for : gather @a -> $x { ... } < 3 { ... } # ick!
if : gather for : gather @a -> $x { ... } < 3 { ... } # ick!**2
for : gather @a -> $x { ... } or @results;
for : gather @a -> $x { ... } or do { ... }

Okay, so the syntax isn't great. I'm just brainstorming.

Having a gather block just feels wrong to me. It's weird to say that
control structure X only has a result when placed inside of a special
block. But maybe it *needs* to be weird.

> On the other hand, putting the default up front is clearer if the
> block is long. Could even be something like:
>
> @foo = gather is default(@results) {
> for @a -> $x { pick $x if mumble($x) }
> }

Hmm.

@foo = for :gather,default(@results) @a -> $x { ... }

Piers Cawley

unread,
Nov 20, 2003, 11:39:51 AM11/20/03
to Smylers, perl6-l...@perl.org
Smylers <Smy...@stripey.com> writes:

It'll be in the summary.

Michael Lazzaro

unread,
Nov 20, 2003, 2:02:56 PM11/20/03
to perl6-l...@perl.org
On Wednesday, November 19, 2003, at 12:28 PM, Smylers wrote:

> Larry Wall writes:
>> : Michael Lazzaro wrote:
>> :
>> : > return if $a { $a }
>>
>> No, it's a syntax error. You must write

> Excellent!

I too was quietly hoping someone would say that. These hurt my
admittedly ever-shrinking brain:

return if $a; # our old friend
return if $a { $a } # ow! me noggin! Always returns, or not?

The C<do> encapsulation helps clarify enormously:

return do { if $a { $a } }

... well, OK, maybe not enormously... I'd still be annoyed if anyone
actually wrote that with a straight face, but there's nothing offensive
about it being legal.

MikeL

Michael Lazzaro

unread,
Nov 20, 2003, 2:23:34 PM11/20/03
to perl6-l...@perl.org

On Tuesday, November 18, 2003, at 12:15 PM, Luke Palmer wrote:
> Oh, and if you really want to do that return thing without using a
> C<given>, you can just:
>
> sub blah {
> return $a || goto CONT;
> CONT:
> ...
> }
>
> I don't see what's wrong with that. :-p

Umm... refresh my/our memory. Did we end up having a post- form of
C<given>, such that:

return $_ if given $big.long.calculation.{ with }{ some }{ stuff };

does what I might suppose it does, or does it have to be... longer?


(The point of that old thread was to try and find the smallest possible
way to write annoyingly common constructs like:

method foo ($self: $a,$b,$c) {
return $self.cached.{ $a }{ $b }{ $c } # short-circuit
calculation,
if $self.cached.{ $a }{ $b }{ $c }; # if possible

... otherwise do actual stuff ...
}

but I don't recall the official recommended solution.)


Forgive the craptacularness of my current P6 knowledge, I have been
preoccupied with life-involving stuff, with items and things and
doohickies.

MikeL

Larry Wall

unread,
Nov 20, 2003, 3:36:31 PM11/20/03
to perl6-l...@perl.org
On Thu, Nov 20, 2003 at 11:23:34AM -0800, Michael Lazzaro wrote:
:
: On Tuesday, November 18, 2003, at 12:15 PM, Luke Palmer wrote:
: >Oh, and if you really want to do that return thing without using a
: >C<given>, you can just:
: >
: > sub blah {
: > return $a || goto CONT;
: > CONT:
: > ...
: > }
: >
: >I don't see what's wrong with that. :-p
:
: Umm... refresh my/our memory. Did we end up having a post- form of
: C<given>, such that:
:
: return $_ if given $big.long.calculation.{ with }{ some }{ stuff };
:
: does what I might suppose it does, or does it have to be... longer?

That'd have to be disallowed because you've nested two statement
modifiers (presuming "given" works like "for"). You'd have to write
something like:

$_ && return $_ given $big.long.calculation.{ with }{ some }{ stuff };

or more properly

defined $_ && return $_ given $big.long.calculation.{ with }{ some }{ stuff };

On the other hand, this may be clearer:

given $big.long.calculation.{ with }{ some }{ stuff } { return $_ // break; }

(But see below.)

Another minor quibble with the construct is that the $_ doesn't really belong to
the given--it uses the outer $_, much like "for", which has the same problem:

print $_ for 1..10;

I think we just have to live with that.

: (The point of that old thread was to try and find the smallest possible

: way to write annoyingly common constructs like:
:
: method foo ($self: $a,$b,$c) {
: return $self.cached.{ $a }{ $b }{ $c } # short-circuit
: calculation,
: if $self.cached.{ $a }{ $b }{ $c }; # if possible
:
: ... otherwise do actual stuff ...
: }
:
: but I don't recall the official recommended solution.)

Well, I'd probably write that as:

method foo ($self: $a,$b,$c) {
return $self.cached.{ $a }{ $b }{ $c } // do {


... otherwise do actual stuff ...
}
}

Larry

Dave Whipp

unread,
Nov 20, 2003, 4:17:40 PM11/20/03
to perl6-l...@perl.org
"Larry Wall" <la...@wall.org> wrote:
> Also, since multi is orthogonal to naming ...

So I'm wondering what the correct syntax is to grab a reference to a group
of multi-somethings. Example:

multi sub foo(Int $a:) {...};
multi sub foo(String $a:) {...};

my $ref = multi &foo;

$ref("hello"); # calls &foo(String)

If this is possible, then $ref is presumably holding some form of junction
of the multi subs. Is it possible to create a similar junction of anonymous
multi-subs?


Dave.


Dan Sugalski

unread,
Nov 20, 2003, 4:37:00 PM11/20/03
to Dave Whipp, perl6-l...@perl.org
On Thu, 20 Nov 2003, Dave Whipp wrote:

> "Larry Wall" <la...@wall.org> wrote:
> > Also, since multi is orthogonal to naming ...
>
> So I'm wondering what the correct syntax is to grab a reference to a group
> of multi-somethings.

While Larry will probably weigh in on this, I'd rather you not actually be
able to do this, at least not to start with. And definitely not the
anonymous version. Maybe for perl 6.2 or 6.4.

Dan

--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk

Luke Palmer

unread,
Nov 20, 2003, 5:26:36 PM11/20/03
to Larry Wall, Damian Conway, perl6-l...@perl.org
Jonathan Scott Duff writes:
> On Wed, Nov 19, 2003 at 12:49:21PM -0800, Larry Wall wrote:
> > Sorry, I wasn't being very clear. It wouldn't be logically attached to
> > the outside of the for, but to the inside of the "confer", or whatever:
> >
> > @foo = gather {
> > for @a -> $x { pick $x if mumble($x) }
> > DEFAULT { @results }
> > }
>
> So ... the only way to get Damians semantics ...
>
> On Wed, Nov 19, 2003 at 08:01:40AM +1100, Damian Conway wrote:
> > * vector control structures like C<loop>, C<while>, and C<for> in
> > a list context return a list of the values of the last statement
> > each iteration evaluated;
> >
> > * vector control structures like C<loop>, C<while>, and C<for> in
> > a scalar context return an integer indicating the number of
> > times their block was iterated.
>
> ... is to surround the control structure with a gather { ... } ??

No. gather{} is a generator (assuming nothing about its name or
existance whatsoever). It runs some code, gathering up each pick()
(same assumption) into a list, and returning that.

If I interpret Larry correctly, Damian's semantics won't be going in.
The way you get each of those is:

my @list = gather {
while $cond {
pick do {...}
}
}

And similarly for each of the other constructs.

But Damian's semantics will work for simple conditionals, it seems.

One wonders what the return value of a loop will be:

my $what = do {
while $cond {...}
}

Luke

Jonathan Scott Duff

unread,
Nov 20, 2003, 8:27:56 PM11/20/03
to Luke Palmer, Larry Wall, Damian Conway, perl6-l...@perl.org
On Thu, Nov 20, 2003 at 03:26:36PM -0700, Luke Palmer wrote:
> No. gather{} is a generator (assuming nothing about its name or
> existance whatsoever). It runs some code, gathering up each pick()
> (same assumption) into a list, and returning that.

Thanks for the post Luke. I'd seen what Larry wrote, but for some
reason it didn't click until you wrote this. I think part of that is
because I was thinking of generators something like this:

sub foo :generator { while $cond { ... yield $foo; } }
@list = &foo;

Where the declaration and use were separate (in my fantasy here,
assigning a coderef to a list makes lazy eval happen). What was
throwing my brain I think it that gather is a declaration and "call"
all rolled into one.

> If I interpret Larry correctly, Damian's semantics won't be going in.
> The way you get each of those is:
>
> my @list = gather {
> while $cond {
> pick do {...}
> }
> }

That makes much more sense the synapse firing that was previously
happening in my head :-)

> One wonders what the return value of a loop will be:
>
> my $what = do {
> while $cond {...}
> }

I would expect it to be the value of the last statement executed.

Larry Wall

unread,
Nov 21, 2003, 8:28:10 PM11/21/03
to perl6-l...@perl.org, Luke Palmer, Damian Conway
On Thu, Nov 20, 2003 at 07:27:56PM -0600, Jonathan Scott Duff wrote:
: On Thu, Nov 20, 2003 at 03:26:36PM -0700, Luke Palmer wrote:
: > One wonders what the return value of a loop will be:

: >
: > my $what = do {
: > while $cond {...}
: > }
:
: I would expect it to be the value of the last statement executed.

Note that Perl 5 interprets it as the value of the last *expression*
evaluated, which for a while loop is going to be some variant of false:

my $what = do {
$cond = 1;
while ($cond) { $cond = 0; 123 }
};
print $what,"\n";
__END__
0

But compare:

my $what = do {
$cond = 0;
until ($cond) { $cond = 1; 123 }
};
print $what,"\n";
__END__
1

Implementation-wise, all that's going on is that the final value on the
expression evaluation stack is magically turned into the return value.
It would take extra effort to remember the result of the last statement
rather than the last expression. And it would be wasted effort most of
the time.

Larry

Piers Cawley

unread,
Nov 25, 2003, 12:37:09 PM11/25/03
to Simon Cozens, Luke Palmer, perl6-l...@perl.org
Simon Cozens <si...@simon-cozens.org> writes:
> Luke Palmer:
>> So modules that introduce new concepts into the language can add new
>> syntax for them without working with (ugh) a source filter. And some of
>> these new syntaxes in the "core" language will actually be in standard
>> modules, if they're not commonly used. Just like traits.
>
> This is good. This is what I like to hear. This is why the answer to
> all these stupid syntax questions should be "Look, if you need it,
> just put it in a module when we're done. But can we please get on
> with getting Perl 6 designed and out the door, now?"
>
> But it isn't, and I don't know why it isn't, and so we end up
> spending loads of time discussing things that can be punted out to
> modules. Designing Perl 6 is hard enough; let's not try to fill
> CP6AN at the same time.

But the vast majority of us *aren't* designing Perl 6, that's Larry
and his team's job. We're in the position of taking the work that's
been done on the language so far and working out how we'd use it (and
yes, we're in the business of thinking about the sort of thing
that will go in CP6AN). Considered in that light, Luke's question is a
really good one, it points up an ugly idiom and considers how one
would generate a better idiom in Perl 6. Where he falls down is in
proposing new syntax to solve the problem rather than in proposing the
new syntax and then offering a sketch of its implementation as a macro
in Perl 6. After all, problems with 'implemented' solutions are simply
demonstrations that the design is sound, and that's good feedback to
Larry and his team. These things only become real design issues if
there appears to be no good way to solve such problems.


Luke Palmer

unread,
Nov 25, 2003, 2:01:23 PM11/25/03
to Piers Cawley, Simon Cozens, perl6-l...@perl.org
Piers Cawley writes:

> Simon Cozens <si...@simon-cozens.org> writes:
> > But it isn't, and I don't know why it isn't, and so we end up
> > spending loads of time discussing things that can be punted out to
> > modules. Designing Perl 6 is hard enough; let's not try to fill
> > CP6AN at the same time.
>
> But the vast majority of us *aren't* designing Perl 6, that's Larry
> and his team's job. We're in the position of taking the work that's
> been done on the language so far and working out how we'd use it (and
> yes, we're in the business of thinking about the sort of thing
> that will go in CP6AN). Considered in that light, Luke's question is a
> really good one, it points up an ugly idiom and considers how one
> would generate a better idiom in Perl 6. Where he falls down is in
> proposing new syntax to solve the problem rather than in proposing the
> new syntax and then offering a sketch of its implementation as a macro
> in Perl 6. After all, problems with 'implemented' solutions are simply
> demonstrations that the design is sound, and that's good feedback to
> Larry and his team. These things only become real design issues if
> there appears to be no good way to solve such problems.

Ok, back to the concrete side of things then. How *would* one implement
a new loop hook?

Let's look at C<while>. It might be implemented as such:

my sub while_impl(&cond, &block) {
my &cc := Continuation.new;
try {
&block.PRE.() if &block.PRE;
if cond() {
block();
throw X::Next;
}
else {
throw X::Last;
}
CATCH {
when X::Next { &block.NEXT.() if &block.NEXT; cc() }
when X::Last { &block.POST.() if &block.POST; }
}
}
}

macro while($cond, $block) {
my (&cond, &block) := ($cond, $block)».«parse;
return -> { while_impl(&cond, &block) }
}

Neglecting things like C<redo>. And so to implement FINISH, you'd need
to stick a C<&block.FINISH.() if &block.FINISH> right before C<throw
X::Last>.

But it would be really nice if you could do this without rewriting
C<while>. One way is to wrap &cond:

wrap &cond: {
call or &_.FINISH.()
};

But then you need to associate FINISH with the condition instead of the
execution block. Or just wrap it when you can see the FINISH block.
Like:

macro FINISH($code) {
# When it's a macro/rule, caller naturally returns the parse stack
CallerContext $c = caller &Perl6::Grammar::while;

my &code := $code.parse;
$c[-1].MY.{'&cond'}.wrap({
call or code()
});
return -> {};
}

Okay, that's pretty evil. Pretty really evil. I took a currently
executing sub, extracted, and I<changed> one of its lexicals. Evil
enough to make the optimizer very unhappy, in any case.

But such is the life of the Aspect-Oriented programmer.

Can anyone think of a cleaner way?

Luke

à

Tom Hyer

unread,
Nov 26, 2003, 6:42:44 AM11/26/03
to
la...@wall.org (Larry Wall) wrote in message news:<20031120203...@wall.org>...

> On the other hand, this may be clearer:
>
> given $big.long.calculation.{ with }{ some }{ stuff } { return $_ // break; }
>
> (But see below.)

What's wrong with the C++ way?

if (my $temp = $big.long.calculation.{ with }{ some }{ stuff })
{ return $temp; }


Tom Hyer

0 new messages