Author: larry
Date: Thu May 31 22:43:55 2007
New Revision: 14411
Modified:
doc/trunk/design/syn/S12.pod
Log:
There is no longer any run-time dwimmery in indirect dispatch.
Now use $obj."$foo" exclusively for symbolic method indirection
$obj.$var and [EMAIL PROTECTED] forms now allow *only* hard refs to Code
objects.
Prefix ops written as postfix no longer use quote form, but $obj.prefix:<+>
$obj.:<+> is allowed as a shorthand for $obj.prefix:<+>
Clarified that all anonymous Code objects are closures, not methods.
WALK pseudo-class is dead. Now just use .WALK method to return candidates.
Modified: doc/trunk/design/syn/S12.pod
==============================================================================
--- doc/trunk/design/syn/S12.pod (original)
+++ doc/trunk/design/syn/S12.pod Thu May 31 22:43:55 2007
@@ -12,9 +12,9 @@
Maintainer: Larry Wall <[EMAIL PROTECTED]>
Date: 27 Oct 2004
- Last Modified: 29 May 2007
+ Last Modified: 31 May 2007
Number: 12
- Version: 53
+ Version: 54
=head1 Overview
@@ -218,15 +218,30 @@
.doit(1,2,3)
-It can use a simple scalar variable for the method name:
+There are several forms of indirection for the method name. You can
+replace the identifier with a quoted string, and it will be evaluated
+as a quote and then the result of that is used as the method name.
- $obj.$methodname(1,2,3)
+ $obj."$methodname"(1,2,3) # use contents of $methodname as method name
+ $obj.'$methodname'(1,2,3) # no interpolation; call method with $ in name!
-The variable may contain either the name of a method or a closure
-object. In the latter case the closure is called with the object
-as its first argument, so that a closure may be used to abstract a
+For situations where you already have a method located, you
+can use a simple scalar variable in place of method name:
+
+ $methodobj = $foo ?? &bar !! &baz;
+ $obj.$methodobj(1,2,3)
+
+or more succinctly but less readably:
+
+ $obj.$($foo ?? &bar !! &baz)(1,2,3)
+
+The variable must contain a Code object, that is, a closure of some
+sort. Regardless of whether the closure was defined as a method or
+a sub or a block, the closure is called as a method, with the object
+as its first argument, and the rest of the arguments second, third,
+and so on. For instance, such a closure may be used to abstract a
"navigational" path through a data structure without specifying the
-root of the path till later.
+root of the path till later:
$locator = -> $root, $x, $y { $root.<foo>[$x]<bar>{$y}[3] }
$obj.$locator(42,"baz") # $obj<foo>[42]<bar><baz>[3]
@@ -234,30 +249,61 @@
$locator = { .<here> }
$obj.$locator # $obj<here>
-The method name may also be quoted with either single or double quotes:
-
- $obj."$methodname"(1,2,3) # same as previous
- $obj.'$methodname'(1,2,3) # call method with $ in name!
+As a convenient form of documentation, such a closure may also be written
+in the form of an anonymous method:
-The latter is especially useful for postfix forms that might be confusing
-to the lexer or to the human reader:
-
- $filename.'+' # same as +$filename.
- .'+' # same as +$_
-
-And in fact, if there is a choice between a unary prefix and a postfix
-operator, the quoted forms will choose the prefix operator. See S03.
-Likewise, presuming that C<$op> does not name an ordinary method on
-C<$left>, this calls any arbitrary infix operator:
+ $locator = method ($root: $x, $y) { $root.<foo>[$x]<bar>{$y}[3] }
+ $obj.$locator(42,"baz") # $obj<foo>[42]<bar><baz>[3]
- $left.$op($right)
+ $locator = method { self.<here> }
+ $obj.$locator # $obj<here>
-Of course you can force that with:
+Note however that, like any anonymous closure, an anonymous method
+can only be dispatched to directly, like a sub. You may, of course,
+bind an anonymous method to the name of a method in a class's public
+interface, in which case it is no longer anonymous, and may be
+dispatched to normally via the class. (And in fact, when the normal
+method dispatcher is calling individual candidates in its candidate
+list, it calls each candidate as a sub, not as a method, or you'd
+end up with recursive dispatchers.) But fundamentally, there's
+no such thing as a method closure. The C<method> declarator on an
+anonymous method has the primary effect of making the declaration
+of the invocant optional. (It also makes it an official C<Routine>
+that can be returned from, just as if you'd used C<sub> to declare it.)
+
+Instead of a scalar variable, an array variable may also be used:
+
+ [EMAIL PROTECTED](1,2,3)
+
+As with the scalar variant, each array element must be a Code object,
+but the list is treated as a list of candidates to call.
+
+Another form of indirection relies on the fact that operators are named
+using a variant on hash subscript notation, which gives you these forms:
+
+ $x.infix:{$op}($y)
+ $x.prefix:{$op}
+ $x.postfix:{$op}
+
+Generally you see these with the literal angle bracket form of subscript:
+
+ $a.infix:<*>($b) # equivalent to $a * $b
+ $a.prefix:<++> # equivalent to ++$a
+ $a.postfix:<++> # equivalent to $a++
+
+If you omit the syntactic category, the call will be dispatched according
+to the number of arguments either as "prefix" or as "infix":
+
+ $a.:<+>($b) # equivalent to $a + $b
+ $a.:<++> # equivalent to ++$a
+ $a.:<!> # equivalent to !$a
+ @a.:<[*]> # equivalent to [*] @a
- $left.infix:{$op}($right)
+But it's probably better to spell out the syntactic category when
+the actual operator is not obvious:
-The C<q> forms of quoting are not allowed for method indirection,
-since they'd be taken as ordinary method names.
+ $x.infix:{$op}($y)
+ $x.prefix:{$op}
You must use a special syntax to call a private method:
@@ -651,7 +697,8 @@
are expected to return a value that can be used as a boolean.
While this is primarily intended for use by file tests, other classes
may define such methods to provide a similar mechanism for interrogating
-properties.
+properties. (Also note that syntactic category names are reserved for
+calling operators as if they were methods.)
Depending on the class, the pairs in question may have arguments.
The C<Hash> class in particular makes use of pair syntax for subscript
@@ -691,12 +738,15 @@
$object."+meth"(@args)
$object.'VAR'(@args)
-The order and selection of the candidates may be
-specified by arguments to a pseudo-class known as C<WALK>:
+As with ordinary calls, the identifier supplying the literal method
+name may be replaced with an interpolated quote to specify the method
+name indirectly. It may also be replaced with an array to specify
+the exact list of candidates to be considered:
- $object.*WALK[:breadth:omit($?CLASS)]::meth(@args);
+ my @candidates := $object.WALK(:name<foo>, :breadth, :omit($?CLASS));
+ [EMAIL PROTECTED](@args);
-The C<WALK> pseudo-class takes these arguments:
+The C<WALK> method takes these arguments:
:canonical # canonical dispatch order
:ascendant # most-derived first, like destruction order
@@ -705,7 +755,7 @@
:breadth # like multi dispatch
:super # only immediate parent classes
- :method<name> # only classes containing method declaration
+ :name<name> # only classes containing named method declaration
:omit(Selector) # only classes that don't match selector
:include(Selector) # only classes that match selector
@@ -770,6 +820,9 @@
$junction.values».meth(@args);
+As with other forms of method call, the "meth" above may be replaced
+with a quoted string or variable to do various forms of indirection.
+
=head1 Multisubs and Multimethods
The "long name" of a subroutine or method includes the type signature