Control flow variables

4 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