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

rvalue "statement" given blocks

0 views
Skip to first unread message

Vincent Pit

unread,
Jan 3, 2010, 1:07:31 PM1/3/10
to perl5-...@perl.org
For some time, I've tried to implement rvalue given blocks. The problem
I met was that allowing given blocks to be expressions led to conflicts
in the grammar : you have no way to tell if "given () ..." should be
parsed with the statement rule (in which case it can be labelled) or the
expression rule (no label is allowed, but it has to end with a semicolon
if another statement follows). The closest I could get was the new
syntax "do given () { }" for the expression form, but it doesn't gain us
much compared to "do { given () { } }".

On Matt's advice, I've extracted all the non-syntaxical part of my
implementation. This allows given statements that are also valid
expressions (think "at the end of a scope", thus "do { given () { } }"
is ok) to return the last evaluated expression before the "given" block
was exitted by reaching the end of a when/default clause or the block
itself. When the block is exitted by "break", an empty list is returned.

In short, this does what you expect :

my $age = do {
given ($name) {
break when /[^\w\s]/;
26 when 'vincent';
'unknown';
}
};

I pushed the change in a new topic branch 'vincent/rvalue_stmt_given' in
the main git repository.

Vincent.

Zefram

unread,
Jan 3, 2010, 2:15:32 PM1/3/10
to perl5-...@perl.org
Vincent Pit wrote:
>For some time, I've tried to implement rvalue given blocks. The problem
>I met was that allowing given blocks to be expressions led to conflicts
>in the grammar
...

>On Matt's advice, I've extracted all the non-syntaxical part of my
>implementation.

+1 on the value-yielding semantics being separate from
statement-as-expression syntax. The semantic change brings "given" in
line with "if" et al, and seems entirely appropriate to include in 5.12,
as rectifying an earlier oversight. It doesn't feel like a new feature.

Statement-as-expression is a wider issue. Whatever is done for "given"
as an expresssion should be done for "if" and other compound statement
types too. Any new syntax here is, of course, an entirely new feature.
I think we should strictly avoid any syntax that leads to ambiguity of
the type Vincent has noted. Probably the cleanest way is to introduce
a new kind of bracketing punctuation:

NEW SYNTAX EQUIVALENT TO

given[($foo) { do { given($foo) {
when(3) { ... } when(3) { ... }
}] } }

if[($a < $b) { do { if($a < $b) {
... ...
}] } }

while[($a < $b) { do { while($a < $b) {
... ...
}] } }

# using TryCatch
try[{ do { try {
... ...
} catch($e) { } catch($e) {
... ...
}] } }

The TryCatch module could just about implement this type of syntax now,
as a prototype. Could certainly do it if reimplemented using the keyword
plugin mechanism. Furthermore, this syntax could be prototyped for "if"
et al by an XS module using the keyword plugin mechanism, modulo some
difficulty in parsing the controlling expression.

-zefram

Mark Mielke

unread,
Jan 3, 2010, 2:27:41 PM1/3/10
to Zefram, perl5-...@perl.org
On 01/03/2010 02:15 PM, Zefram wrote:
> Statement-as-expression is a wider issue. Whatever is done for "given"
> as an expresssion should be done for "if" and other compound statement
> types too. Any new syntax here is, of course, an entirely new feature.
> I think we should strictly avoid any syntax that leads to ambiguity of
> the type Vincent has noted. Probably the cleanest way is to introduce
> a new kind of bracketing punctuation:
>
> NEW SYNTAX EQUIVALENT TO
>
> given[($foo) { do { given($foo) {
> when(3) { ... } when(3) { ... }
> }] } }
>
> if[($a< $b) { do { if($a< $b) {
> ... ...
> }] } }
> ...

What's the value of this, "given" that do{} exists today? Yet another
syntax that may save a few characters at the expense of brain cells? :-)

If you must introduce new syntax, I'd suggest something like GCC's ({
... }). The () clearly suggests it is an expression. The {} clearly
points out that it is a block. If ({ ... }) became a generate substitute
for do {}, I would not complain as I think it communicates intent (self
documenting code) more effectively.

But ... it shouldn't be just to introduce new syntax. People must
believe that do{} is problematic in some way, otherwise it's complexity
without reason. do{NAME...} vs NAME[...] has only saved two characters
and do{NAME...} vs ({NAME...}) has not saved any characters.

Cheers,
mark

--
Mark Mielke<ma...@mielke.cc>

Eric Brine

unread,
Jan 3, 2010, 2:51:43 PM1/3/10
to pe...@profvince.com, perl5-...@perl.org
On Sun, Jan 3, 2010 at 1:07 PM, Vincent Pit <pe...@profvince.com> wrote:

> For some time, I've tried to implement rvalue given blocks. The problem I
> met was that allowing given blocks to be expressions led to conflicts in the
> grammar : you have no way to tell if "given () ..." should be parsed with
> the statement rule (in which case it can be labelled) or the expression rule
> (no label is allowed, but it has to end with a semicolon if another
> statement follows).


It seems to me you could do something like

stmt : label stmt_
| stmt_

stmt_ : flow_ctrl
| expr ";"

expr : flow_ctrl
| ...

flow_ctrl : for
| while
| for
| ...

(Well, the semi-colon isn't optional there, but you get the idea)

Zefram

unread,
Jan 3, 2010, 3:38:27 PM1/3/10
to perl5-...@perl.org
Eric Brine wrote:
>It seems to me you could do something like

No, you can't. What would this return:

sub break_eric() {
if(1) { 123 }
+1;
}

It's already legal (returning 1), but if the "+" causes the "if" statement
to be interpreted as an expression then it'd return 124 instead.

-zefram

Zefram

unread,
Jan 3, 2010, 3:31:53 PM1/3/10
to perl5-...@perl.org
Mark Mielke wrote:
>What's the value of this, "given" that do{} exists today?

do{} ends with a closing brace, which looks more like the end of
a compound statement than the end of an expression. eval{} has the
same problem. It's syntactically preferable for an expression to end
with something that "looks like" it ought to be followed by a semicolon
or infix operator. Parens (which would be my first choice for looking
expressionish) are unavailable, because parens (and multiple parens)
following "if" et al already have meaning.

Also, the extra keyword "do" of do{} draws unwarranted attention to the
process of embedding a compound statement in an expression. We want
the main attention to be on the structure of the statement itself.

>If you must introduce new syntax, I'd suggest something like GCC's ({
>... }). The () clearly suggests it is an expression.

Would be nice, except that {...} already has meaning in an expression
context, as a hash constructor. Step away from the ambiguity. However,
that problem doesn't apply to keyword-headed compound statements.
You could do

NEW SYNTAX EQUIVALENT TO
(if($a < b) { ... }) do { if($a < $b) { ... } }

and the same for "while", "given", et al. A substantial downside is
that you then have expressions of the form "(...)" where the "..." is not
itself an expression. Editing errors are inevitable. It's also rather
unlike existing Perl syntax in that the controlling keyword is contained
within the bracketing punctuation, rather than coming first as usual.

-zefram

Ben Morrow

unread,
Jan 3, 2010, 5:12:06 PM1/3/10
to zef...@fysh.org, perl5-...@perl.org
Quoth zef...@fysh.org (Zefram):

The usual way to say 'this is a term' in Perl is unary +, which would
give

+if ($a < $b) { ... } do { if ($a < $b) {...} }

I believe this is currently illegal, though unary + may be considered
obscure enough not to want to promote its use further.

Ben

Zefram

unread,
Jan 3, 2010, 5:59:09 PM1/3/10
to perl5-...@perl.org
Ben Morrow wrote:
>The usual way to say 'this is a term' in Perl is unary +,

This is less nice than enclosing in parens. It has the same problem as
parens that it is ordinarily used with something that could be parsed as
an expression: + is used to disambiguate braces as a hash constructor,
for which purpose other expressionish hints would work just as well.
Unlike parens, it fails to make clear where the expression ends, and it
results in the expression ending with the closing brace of a code block,
which as previously noted is confusing.

-zefram

Eric Brine

unread,
Jan 3, 2010, 6:10:03 PM1/3/10
to Zefram, perl5-...@perl.org

Not according to the grammar I posted. It's a statement if it starts with a
flow control. As such, the above returns the result of second statement
("+1;"). You can disambiguate as follows:

do { if (1) { 123 } } + 1 124
+if (1) { 123 } + 1 124
1 + if (1) { 123 } 124

Zefram

unread,
Jan 3, 2010, 6:18:12 PM1/3/10
to perl5-...@perl.org
Eric Brine wrote:
>Not according to the grammar I posted.

The grammar you posted was ambiguous in precisely this manner, and you
didn't specify how to resolve the ambiguity. Perhaps you elided more
than you intended to?

Anyway. Making the grammar more ambiguous and then adding a
disambiguating rule to recover seems like a backward step. What you
propose (whichever way disambiguated) would make code harder to read
and increase the incidence of editing errors.

-zefram

Aristotle Pagaltzis

unread,
Jan 3, 2010, 7:59:08 PM1/3/10
to perl5-...@perl.org
* Zefram <zef...@fysh.org> [2010-01-03 20:15]:

> Statement-as-expression is a wider issue. Whatever is done for
> "given" as an expresssion should be done for "if" and other
> compound statement types too.

Most block statements already have some accidental return value,
and there is probably code relying on them. If you want to change
that, the new behaviour will have to be a feature.

Other than that niggle though, I am in favour.

> Any new syntax here is, of course, an entirely new feature.
> I think we should strictly avoid any syntax that leads to
> ambiguity of the type Vincent has noted. Probably the cleanest

> way is to introduce Probably the cleanest way is to introduce


> a new kind of bracketing punctuation:
>
> NEW SYNTAX EQUIVALENT TO
>
> given[($foo) { do { given($foo) {
> when(3) { ... } when(3) { ... }
> }] } }

Probably the ugliest too, good grief.

Regards,
--
Aristotle Pagaltzis // <http://plasmasturm.org/>

Eric Brine

unread,
Jan 3, 2010, 10:45:00 PM1/3/10
to Zefram, perl5-...@perl.org
On Sun, Jan 3, 2010 at 6:18 PM, Zefram <zef...@fysh.org> wrote:

> Eric Brine wrote:
> >Not according to the grammar I posted.
>
> The grammar you posted was ambiguous in precisely this manner, and you
> didn't specify how to resolve the ambiguity.


First prod first

Mark Mielke

unread,
Jan 4, 2010, 12:32:44 AM1/4/10
to Zefram, perl5-...@perl.org
On 01/03/2010 03:31 PM, Zefram wrote:
> Mark Mielke wrote:
>
>> What's the value of this, "given" that do{} exists today?
>>
> do{} ends with a closing brace, which looks more like the end of
> a compound statement than the end of an expression. eval{} has the
> same problem. It's syntactically preferable for an expression to end
> with something that "looks like" it ought to be followed by a semicolon
> or infix operator. Parens (which would be my first choice for looking
> expressionish) are unavailable, because parens (and multiple parens)
> following "if" et al already have meaning.
>

This is pretty long standing Perl syntax. If people don't know that
"last expression is the return" for a block - then they don't really
know Perl?

> Also, the extra keyword "do" of do{} draws unwarranted attention to the
> process of embedding a compound statement in an expression. We want
> the main attention to be on the structure of the statement itself.
>

Two characters distract? What of the statement that the do{} is embedded
within? :-)

>> If you must introduce new syntax, I'd suggest something like GCC's ({
>> ... }). The () clearly suggests it is an expression.
>>
> Would be nice, except that {...} already has meaning in an expression
> context, as a hash constructor. Step away from the ambiguity. However,
> that problem doesn't apply to keyword-headed compound statements.
>

Of course - I didn't much think about the suggestion beyond liking it in
GCC. Oops.

> You could do
>
> NEW SYNTAX EQUIVALENT TO
> (if($a< b) { ... }) do { if($a< $b) { ... } }
>
> and the same for "while", "given", et al. A substantial downside is
> that you then have expressions of the form "(...)" where the "..." is not
> itself an expression. Editing errors are inevitable. It's also rather
> unlike existing Perl syntax in that the controlling keyword is contained
> within the bracketing punctuation, rather than coming first as usual.
>

For the above example - I do not see improvement over:

($a < $b) && do { ... }

The example is a bit impractical as I doubt people intend to return
undef if $a >= $b.

The new syntax does not look clearer to me - just more brief, context
dependent, and therefore of limited use. I guess I don't see the problem
with do{}. Just as one and perhaps generalize that "whatever is done to
given should also be done to the other control structures", one should
perhaps also generalize that "whatever is done to given should apply to
any type of code block". Use of do{} is an example of a syntax that
works today. A true generalization should be an alias for do{}, not an
alias for control structures only. It should also support:

do { my $temp = $_; $temp =~ s/.../.../g; ...; $temp }

I didn't catch the beginning of the thread, but I take it you want to do:

$result = given($foo) {
when (1) { "one" }
when (2) { "two" }
default { "default" }
};

I recall discussion over this when it was being introduced. I didn't
really care either way and didn't pay much attention - but it sounds
familiar, like this has been discussed before. :-)

Is given() special enough to be an operand instead of a control structure?

I think discussion over generalization to other control structures or
blocks suggests that given() is not truly special, and some people
believe that all control structures or blocks should be given the
ability to be promoted to an expression with briefer syntax than
wrapping the structure in do{}.

Alternatively, it should not be generalized. given() is truly special,
and deserves special support. given() should be implemented like do{} or
map{}, and use in a void context is just a special case.

Dr.Ruud

unread,
Jan 3, 2010, 6:53:14 PM1/3/10
to perl5-...@perl.org
Eric Brine wrote:

> do { if (1) { 123 } } + 1 124

perl -wle'
print do { if (1) { "foo" } } ."bar";
'
foobar


perl -wle'
print do { if (0) { "foo" } } ."bar";
'
0bar


$ perl -wle'
print do { if ($ARGV[0]) { "foo" } } ."bar";
' 1
foobar


perl -wle'
print do { if ($ARGV[0]) { "foo" } } ."bar";
' 0
0bar

--
Ruud

David Nicol

unread,
Jan 4, 2010, 2:44:59 PM1/4/10
to perl5-...@perl.org
Well done Vincent!

As there is already a big digression on new syntax here, I'm in favor
of allowing expression post-modifiers (if,while,for,unless) which are
all currently allowed only one per expression, to stack to any depth,
if nobody strenuously objects, while we're suggesting new syntax.

Aristotle Pagaltzis

unread,
Jan 4, 2010, 5:32:33 PM1/4/10
to perl5-...@perl.org
* David Nicol <david...@gmail.com> [2010-01-04 20:45]:

I’d like that too, but apparently Larry explicitly restricted
them. However, I’d be strongly in favour of doing the same thing
as Perl 6: allow one conditional modifier and one loop modifier
to be stacked. That covers 99% of the cases where I wish they
were allowed to stack, anyway.

Shlomi Fish

unread,
Jan 5, 2010, 5:55:30 AM1/5/10
to perl5-...@perl.org, Aristotle Pagaltzis

"42.7% of all statistics are made up on the spot."

-- http://www.steven-wright.com/

;-)

Regards,

Shlomi Fish

> Regards,
>

--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/
Freecell Solver - http://fc-solve.berlios.de/

Bzr is slower than Subversion in combination with Sourceforge.
( By: http://dazjorz.com/ )

Aristotle Pagaltzis

unread,
Jan 5, 2010, 12:03:43 PM1/5/10
to David Nicol, perl5-...@perl.org
Hi David,

* David Nicol <david...@gmail.com> [2010-01-05 17:45]:


> On Mon, Jan 4, 2010 at 4:32 PM, Aristotle Pagaltzis <paga...@gmx.de> wrote:
> >I’d like that too, but apparently Larry explicitly restricted
> >them. However, I’d be strongly in favour of doing the same
> >thing as Perl 6: allow one conditional modifier and one loop
> >modifier to be stacked. That covers 99% of the cases where
> >I wish they were allowed to stack, anyway.
>

> but the question remains, on what basis did Larry explicitly
> restrict them?
>
> I think the basis was the difficulty of changing the existing
> implementation.

No. And that isn’t even plausible if you consider two facts:

• In BASIC-PLUS, where the idea came from, modifiers are freely
stackable.

• If Larry didn’t *want* the restriction, why would he decide
that Perl 6, free from concerns of an existing implementation,
should yet have almost the same restriction?

It was an intentional design choice. Implementation difficulty
was not the reason.

> When I ever get around to writing my Perl compiler, which will
> be heavily bases on multiple stages of rewrite rules, it will
> allow them, as using that approach it is simpler to allow them
> then to disallow them.

Yes, it is simpler. Larry went out of his way to disallow stacked
modifiers, even in Perl 5.

0 new messages