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

[svn:perl6-synopsis] r13582 - doc/trunk/design/syn

3 views
Skip to first unread message

la...@cvs.perl.org

unread,
Feb 12, 2007, 3:10:06 AM2/12/07
to perl6-l...@perl.org
Author: larry
Date: Mon Feb 12 00:10:05 2007
New Revision: 13582

Modified:
doc/trunk/design/syn/S02.pod
doc/trunk/design/syn/S04.pod
doc/trunk/design/syn/S06.pod

Log:
The kludge known as "leave" is now spelled "give".
The give() function always gives the final value of the innermost block.
The $context.give() method always gives the final value of the context.
Rather than repeating the context selector interface we now rely on object.
Loop labels are now considered sufficient OO to allow LABEL.give($retval)
within the *lexical* scope of the labeled statement.


Modified: doc/trunk/design/syn/S02.pod
==============================================================================
--- doc/trunk/design/syn/S02.pod (original)
+++ doc/trunk/design/syn/S02.pod Mon Feb 12 00:10:05 2007
@@ -12,9 +12,9 @@

Maintainer: Larry Wall <la...@wall.org>
Date: 10 Aug 2004
- Last Modified: 8 Feb 2007
+ Last Modified: 11 Feb 2007
Number: 2
- Version: 85
+ Version: 86

This document summarizes Apocalypse 2, which covers small-scale
lexical items and typological issues. (These Synopses also contain
@@ -2468,7 +2468,21 @@

The lexical routine itself is C<&?ROUTINE>; you can get its name with
C<&ROUTINE.name>. The current block is C<&?BLOCK>. If the block has a label,
-that shows up in C<&?BLOCK.label>.
+that shows up in C<&?BLOCK.label>. Within the lexical scope of
+a statement with a label, the label is a pseudo-object representing
+the dynamic context of that statement. (If inside multiple dynamic
+instances of that statement, the label represents the innermost one.)
+When you say:
+
+ next LINE;
+
+it is really a method on this pseudo-object, and
+
+ LINE.next;
+
+would work just as well. You can exit any labeled block early by saying
+
+ MyLabel.give(@results);

=item *

Modified: doc/trunk/design/syn/S04.pod
==============================================================================
--- doc/trunk/design/syn/S04.pod (original)
+++ doc/trunk/design/syn/S04.pod Mon Feb 12 00:10:05 2007
@@ -12,9 +12,9 @@

Maintainer: Larry Wall <la...@wall.org>
Date: 19 Aug 2004
- Last Modified: 8 Feb 2007
+ Last Modified: 11 Feb 2007
Number: 4
- Version: 51
+ Version: 52

This document summarizes Apocalypse 4, which covers the block and
statement syntax of Perl.
@@ -204,7 +204,8 @@
within the body of the loop. See below.

The value of a loop statement is the list of values from each
-iteration. (This list is actually a multidimensional list (a "multislice")
+iteration that successfully completed without a C<next> or C<last>.
+(This list is actually a multidimensional list (a "multislice")
with dimensional boundaries at each iteration. Most list contexts
ignore these boundaries and flatten the list.) If you do not wish
to accidentally return a list from the final loop statement in a
@@ -651,26 +652,49 @@
with the C<sub>, C<method>, or C<submethod> keywords). Pointy blocks
and bare closures are transparent to C<return>. If you pass a closure
object outside of its official "sub" scope, it is illegal to
-return from it. You may only leave the closure block itself with C<leave>
-or by falling off the end of it.
+return from it. You may only leave the displaced closure block itself
+by falling off the end of it or by explicitly calling C<give>.

-To return a value from a pointy block or bare closure, you either
-just let the block return the value of its final expression, or you can
-use C<leave>. A C<leave> by default exits from the innermost block.
-But you may change the behavior of C<leave> with a selector as the
-first argument:
+To return a value from any pointy block or bare closure, you either
+just let the block return the value of its final expression, or you
+can use C<give>, which comes in both function and method forms.
+The function (or listop) form always exits from the innermost block,
+returning its arguments as the final value of the block exactly as
+return does. The method form will leave any block in the dynamic
+scope that can be named as an object and that responds to the C<.give>
+method.

- leave Loop where { .label ~~ 'LINE' }, 1,2,3;
+Hence, the C<give> function:

-The innermost block matching the selection criteria will be exited.
-The return value, if any, must be passed as the second and subsequent arguments.
-To return pairs as part of the value, you can use a feed operator:
+ give(1,2,3)

- leave <== :foo:bar:baz(1) if $leaving;
+is really just short for:

-or going the other way:
+ $?BLOCK.give(1,2,3)

- $leaving and :foo:bar:baz(1) ==> leave;
+To return from your immediate caller, you can say:
+
+ caller.give(1,2,3)
+
+Further contexts up the caller stack may be located by the selector
+that is built into the C<caller> function itself:
+
+ caller({ .label eq 'LINE' }).give(1,2,3);
+
+By default the innermost dynamic scope matching the selection criteria
+will be exited. This can be a bit cumbersome, so in the particular
+case of labels, the label that is already visible in the current lexical
+scope is considered a kind of pseudo object specifying a potential
+dynamic context. If instead of the above you say:
+
+ LINE.give(1,2,3)
+
+it was always exit from your lexically scoped C<LINE> loop, even
+if some inner dynamic scope you can't see happens to also have that
+label. If the C<LINE> label is visible but you aren't actually in
+a dynamic scope controlled by that label, an exception is thrown.
+(If the C<LINE> is not visible, it would have been caught earlier at
+compile time since C<LINE> would likely be a bareword.)

In theory, any user-defined control construct can catch any control
exception it likes. However, there have to be some culturally enforced
@@ -680,8 +704,10 @@
expects it to be caught by. In particular, if the user labels a loop
with a specific label, and calls a loop control from within the lexical
scope of that loop, and if that call mentions the outer loop's label,
-then that outer loop is the one that must be controlled. (This search
-of lexical scopes is limited to the current "official" subroutine.)
+then that outer loop is the one that must be controlled. In other words,
+it first tries this form:
+
+ LINE.give(1,2,3)

If there is no such lexically scoped outer loop in the current subroutine,
then a fallback search is made outward through the dynamic scopes in
@@ -690,7 +716,8 @@
control structures, hence the sub's lexical scope was I<always>
the innermost dynamic scope, so the preference to the lexical scope
in the current sub was implicit. For Perl 6 we have to make this
-preference explicit.)
+preference explicit.) So this fallback is more like the C<caller>
+form we saw earlier.

Warnings are produced in Perl 6 by throwing a resumable control
exception to the outermost scope, which by default prints the

Modified: doc/trunk/design/syn/S06.pod
==============================================================================
--- doc/trunk/design/syn/S06.pod (original)
+++ doc/trunk/design/syn/S06.pod Mon Feb 12 00:10:05 2007
@@ -13,9 +13,9 @@

Maintainer: Larry Wall <la...@wall.org>
Date: 21 Mar 2003
- Last Modified: 29 Jan 2007
+ Last Modified: 11 Feb 2007
Number: 6
- Version: 68
+ Version: 69


This document summarizes Apocalypse 6, which covers subroutines and the
@@ -826,8 +826,8 @@
=head2 Feed operators

The variadic list of a subroutine call can be passed in separately from
-the normal argument list, by using either of the I<feed> operators: C<<
-<== >> or C<< ==> >>. Syntactically, feed operators expect to find a
+the normal argument list, by using either of the I<feed> operators:
+C<< <== >> or C<< ==> >>. Syntactically, feed operators expect to find a
statement on either end. Any statement can occur on the source end;
however not all statements are suitable for use on the sink end of a feed.

@@ -852,16 +852,39 @@
but differ in interface. Code which violates these promises is
erroneous, and will produce undefined results when parallelized.)

-In particular, a chain of feeds may not begin and end with the same array.
-(You may, however, assign to an array that is used within a chain
-on the right side of the assignment, since list assignment will clear
-and copy as necessary to make it work.) That is, this doesn't work:
+However, feeds go a bit further than ordinary lazy lists in enforcing
+the parallel discipline: they explicitly treat the blunt end as a
+cloned closure that starts a subthread. The only variables shared
+by the inner scope with the outer scope are those lexical variables
+declared in the outer scope that are visible at the time the closure is
+cloned and the subthread spawned. Use of such shared variables will
+automatically be subject to transactional protection (and associated
+overhead). Package variables are not cloned unless predeclared
+as lexical names with C<our>. Variables declared within the blunt
+end are not visible outside, and in fact it is illegal to declare a
+lexical on the blunt end that is not enclosed in curlies somehow.
+
+Because feeds are defined as lazy pipes, a chain of feeds may not begin
+and end with the same array without some kind of eager sequence point.
+That is, this doesn't work:

+ my @data = 1,2,3;
@data <== grep { $_ % 2 } <== @data;

but this does:

- @data = grep { $_ % 2 } <== @data;
+ my @data = 1,2,3;
+ my @tmp = eager @data;
+ @data <== grep { $_ % 2 } <== @tmp;
+
+(But note: feed operators have push semantics when the receiver is an array.
+Use assignment to get clear-first semantics.)
+
+Conjecture: these are probably impossible:
+
+ @data <== grep { $_ % 2 } <== eager @data;
+ @data = do { grep { $_ % 2 } <== eager @data; }
+ @data := do { grep { $_ % 2 } <== eager @data; }

Leftward feeds are a convenient way of explicitly indicating the typical
right-to-left flow of data through a chain of operations:
@@ -875,8 +898,9 @@
Rightward feeds are a convenient way of reversing the normal data flow in a
chain of operations, to make it read left-to-right:

- @oddsquares = do
- @nums ==> grep { $_ % 2 } ==> sort ==> map { $_**2 };
+ @oddsquares = do {
+ @nums ==> grep { $_ % 2 } ==> sort ==> map { $_**2 };
+ }

Note that the C<do> is necessary because feeds operate at the statement
level. (Parens would also work, since a "do" is assumed there.)
@@ -1587,7 +1611,7 @@
blocks this can be optimized away to a "goto". All C<Routine> declarations
have an explicit declarator such as C<sub> or C<method>; bare blocks and
"pointy" blocks are never considered to be routines in that sense. To return
-from a block, use C<leave> instead--see below.
+from a block, use C<give> instead--see below.

The C<return> function preserves its argument list as a C<Capture> object, and
responds to the left-hand C<Signature> in a binding. This allows named return
@@ -1650,7 +1674,8 @@
$caller = caller Method; # nearest caller that is method
$caller = caller Bare; # nearest caller that is bare block
$caller = caller Sub, :skip(2); # caller three levels up
- $caller = caller Block, :label<Foo>; # caller whose label is 'Foo'
+ $caller = caller Block where { .label eq 'Foo' };
+ # caller whose label is 'Foo'

=head2 The C<want> function

@@ -1688,38 +1713,48 @@
# want.arity === 0
# want.count === 2

-=head2 The C<leave> function
+=head2 The C<give> function

-As mentioned above, a C<return> call causes the innermost
-surrounding subroutine, method, rule, token, regex (as a keyword)
-or macro to return. Only declarations with an explicit
-keyword such as "sub" may be returned from. You may not return from
-a quotelike operator such as C<rx//>.
-
-To return from other types of code structures, the C<leave> function
-is used. The first argument, if supplied, specifies a C<Selector>
-for the control structure to leave. The C<Selector> will be
-smart-matched against the dynamic scope objects from inner to outer.
-The first that matches is the scope that is left.
+As mentioned above, a C<return> call causes the innermost surrounding
+subroutine, method, rule, token, regex (as a keyword) or macro to
+return. Only declarations with an explicit keyword such as "sub"
+may be returned from. You may not use C<return> to return from loops,
+bare blocks, pointy blocks, or quotelike operators such as C<rx//>.
+
+To return from these types of code structures, the C<give> method
+is used instead. (It can be taken to mean either "give up" or
+"bequeath" as appropriate.) The object specifies the scope to exit,
+and the method's arguments specify the return value. If the object
+is omitted (by use of the function or listop forms), the innermost
+block is exited. Otherwise you must use something like C<caller>
+or C<$?BLOCK> or a contextual variable to specify the scope you
+want to exit. A label (such as a loop label) previously seen in
+the lexical scope also works as a kind of singleton context object:
+it names a statement that is serving both as an outer lexical scope
+and as a context in the current dynamic scope.

-The remainder of the arguments are taken to be a C<Capture> holding the
+As with C<return>, the arguments are taken to be a C<Capture> holding the
return values.

- leave; # return from innermost block of any kind
- leave *; # same thing
- leave Method; # return from innermost calling method
- leave &?ROUTINE, 1,2,3; # Return from current sub. Same as: return 1,2,3
- leave &?ROUTINE <== 1,2,3; # same thing, force return as feed
- leave &foo, 1,2,3; # Return from innermost surrounding call to &foo
+ give; # return from innermost block of any kind
+ caller(Method).give; # return from innermost calling method
+ &?ROUTINE.give(1,2,3); # Return from current sub. Same as: return 1,2,3
+ &?ROUTINE.give <== 1,2,3; # same thing, force return as feed
+ OUTER.give; # Return from OUTER label in lexical scope
+ &foo.give: 1,2,3; # Return from innermost surrounding call to &foo

-Note that these are equivalent:
+Note that these are equivalent in terms of control flow:

- leave Loop where { .label eq 'COUNT' };
+ COUNT.give;
last COUNT;

-and, in fact, you can return a final loop value that way:
+However, the first form explicitly gives the return value for the
+entire loop, while the second implicitly returns all the previous
+successful loop iteration values as a list comprehension. A C<give>
+from the inner loop block, however, merely specifies the return value for
+that iteration:

- last COUNT, 42;
+ for 1..10 { give $_ * 2 } # 2..20

=head2 Temporization

Larry Wall

unread,
Feb 12, 2007, 2:29:05 AM2/12/07
to perl6-l...@perl.org
Oh, I neglected to log the clarifications to feed operators to make
it clear that their intent is to allow for massive parallelism with
a minimum of sharing, more on the Unix pipe model than the "share
everything" model. Some implicit sharing is possible via lexical
closure at thread creation time, but globals and package variables
are specifically not shared unless declared with "our" prior to
the "fork".

This decoupling is also part of why they were hoisted out of operator
precedence operators into statement separators, more like Unix shell.
We want to more easily be able to take advantage of new parallel
architectures such as the Cell. This view of feeds is also much
more in line with the event model view of reality as espoused by
languages like Tcl and Erlang. (We have also the async {} block for
more traditional shared-data threads. For an interesting read on
combining traditional threading and event models in the same process,
see http://www.seas.upenn.edu/~lipeng/homepage/unify.html.)

Larry

Smylers

unread,
Feb 12, 2007, 4:38:45 PM2/12/07
to perl6-l...@perl.org
la...@cvs.perl.org writes:

> +++ doc/trunk/design/syn/S06.pod Mon Feb 12 00:10:05 2007

> + Version: 69
>
> ... this does [work]:


>
> + my @data = 1,2,3;

> + my @tmp = eager @data;
> + @data <== grep { $_ % 2 } <== @tmp;
> +

> +Conjecture: these are probably impossible:
> +
> + @data <== grep { $_ % 2 } <== eager @data;

Surely that's the form that folks will actually want?

With no supporting data at all I'm going to claim it's reasonably common
to want to filter an array without any need to keep the original around;
having the Perl 6 idiom for that involve a temporary array seems rather
ugly, exactly the sort of awkwardness that Perl 6 is eliminating
elsewhere.

Smylers

Larry Wall

unread,
Feb 12, 2007, 7:06:44 PM2/12/07
to perl6-l...@perl.org
On Mon, Feb 12, 2007 at 09:38:45PM +0000, Smylers wrote:
: la...@cvs.perl.org writes:
:
: > +++ doc/trunk/design/syn/S06.pod Mon Feb 12 00:10:05 2007
: > + Version: 69
: >
: > ... this does [work]:
: >
: > + my @data = 1,2,3;
: > + my @tmp = eager @data;
: > + @data <== grep { $_ % 2 } <== @tmp;
: > +
: > +Conjecture: these are probably impossible:
: > +
: > + @data <== grep { $_ % 2 } <== eager @data;
:
: Surely that's the form that folks will actually want?

Oh, I don't doubt it. But people want the darnedest things sometimes...

The basic problem here is that mutable data is coupled to realtime
but lazy data is decoupled.

: With no supporting data at all I'm going to claim it's reasonably common


: to want to filter an array without any need to keep the original around;
: having the Perl 6 idiom for that involve a temporary array seems rather
: ugly, exactly the sort of awkwardness that Perl 6 is eliminating
: elsewhere.

The key phrase there is "without any need to keep the original around".
It's possible we can make the syntax work, but we have to be very
careful to be clear about the identity of the container and its data.
It's one thing to say

$x = $x + 1;

where you know that the value of $x on the right can be read atomically
before $x gets clobbered on the left. List assignment was a bad enough
problem in Perl 5, where things like

($a,$b) = ($b,$a)

have to be smart enough to copy to a temporary list for you. In Perl 6
we have the additional factor that lists are lazy by default, so it's
not at all clear that

@data = filter(@data)

starts reading from the right @data before left @data null the
array and starts reading the list on the right.

However, with <== we have something else going for us, which is that
we've defined the pointy end to basically be a binding rather than an
assignment. So the trick to making the loop work is to not actually
have a loop. In order to make it work, we essentially no longer
think of @data so much as a mutable value, but more as a bindable
container, and

@data <== filter(@data)
filter(@data) ==> @data

are really doing something more like

my @data := filter(@data)

except that the latter doesn't actually work because the my clobbers
the variable name lexically. So maybe we can make the loop work as
long as we guarantee the rebinding of the pointy end always happens
after the forking and binding of the blunt end. Basically the blunt
end gives away the old variable to the subthread that is going to
filter it into the the list of values, and the sharp end rebinds the
name to a new container.

That's the only way I see it working right now.

Larry

0 new messages