Here's a message I posted to the cabal last week a couple of days after our design meetings, in which we discussed the method lookahead issue. This message resolves those issues as well as how adverbs are parsed. Eventually this information will find its way into S12, when we get around to writing it.
Larry Date: Wed, 4 Aug 2004 10:13:27 -0700 From: Larry Wall <[EMAIL PROTECTED]> Subject: resolution of method argument parsing issues Okay, after mulling over this for two days and going over the same mental ground repeatedly, I've come to some conclusions. First, it's a mistake to try to make methods and functions parse the same. Once I get that bee out of my bonnet, I am free to say they work different (compare 1 with 2): 1) In the absence of evidence to the contrary, functions always assume they're list operators. For functions: 1a) Unary and zero-ary functions will parse specially only if there is an appropriate non-multi declaration, as in Perl 5. $later = time + 20; 1b) The predeclaration of multis has no effect on parsing. They are always parsed as list operators. Undeclared functions are assumed to be multies, and can therefore be written in either functional or listop notation. 1c) Explicit parentheses may delimit the actual arguments, in which case the function is parsed as a function rather than a list operator. Adverbs may follow the parens: splurt(1,2,3):by{ +$_ } # okay splurt(1,2,3):{ +$_ } # okay (implicit binding to *& param) splurt 1,2,3 # okay (assumed to be list operator) splurt; # okay, 0-arg list splurt() + 1 # okay, explicit 0 arg list splurt + 1 # wrong unless predeclared 0-ary 1d) Additional arguments may occur as adverbs *only* if there are explicit parens. (Or in the absence of parens they may parse as arguments when a term is expected--but then they're not adverbs, just named arguments...) splurt():by{ +$_ } # okay splurt 1,2,3 :by{ +$_ } # ILLEGAL (comma rejects the adverb) splurt 1,2,3 :{ +$_ } # ILLEGAL (comma rejects the adverb) splurt 1,2,3,:{ +$_ } # likely okay (as anonymous named param) splurt :{ +$_ } # likely okay (as anonymous named param) splurt { +$_ } # okay (positional param) splurt 1,2,3, { +$_ } # okay (positional param) 2) In the absence of evidence to the contrary, methods always assume they have *no* arguments. For methods: 2a) A method not followed by a left paren or colon has no arguments. 2b) As with multies, method declarations can have no effect on the parsing of methods. Unlike multis, the default is no arguments. 2c) The only way to pass arguments to a method is by an explicitly parenthesized list or by adverb. Or by both. .splurt(1,2,3):by{ +$_ } # okay .splurt(1,2,3):{ +$_ } # okay (implicit binding to *& param) .splurt 1,2,3 # ILLEGAL .splurt; # okay, 0-arg list .splurt() + 1 # okay, explicit 0 arg list .splurt + 1 # okay 2d) Given 2c, additional arguments may occur as adverbs whether or not there is an argument "pill": .splurt():by{ +$_ } # okay .splurt 1,2,3 :by{ +$_ } # ILLEGAL (no term expected) .splurt 1,2,3 :{ +$_ } # ILLEGAL (no term expected) .splurt 1,2,3,:{ +$_ } # ILLEGAL (parens required) .splurt :{ +$_ } # okay (as adverb--no term expected) .splurt { +$_ } # ILLEGAL (parens required) .splurt 1,2,3, { +$_ } # ILLEGAL (parens required) 3) A bare {...} where an operator is expected always terminates the current list operator, and takes the precedence level back to statement level. That is, it pops all the implicit left parentheses of list operators with implicit right parentheses. if print sort { +$_ }, @foo {...} if print(sort({ +$_ }, @foo)) {...} # same thing 3a) Note that an operator {...} cannot occur in the arguments of either a function or a method. Operator {...} is reserved for statement level control flow blocks. if blurk {...} {...} # 1st closure is arg, 2nd ifblock if blurk(1) {...} # closure is ifblock if blurk 1 {...} # closure is ifblock if .blurk {...} # closure is ifblock if .blurk {...} {...} # 1st is ifblock, 2nd is bare block? if .blurk:{...} {...} # 1st closure is adverb, 2nd ifblock if .blurk(1) {...} # closure is ifblock if .blurk 1 {...} # ILLEGAL 3b) Term {...} cannot assume a comma after it if the next thing is a closure. Otherwise the first line under 3a breaks. The fifth line with a bare block is a bit problematic as a silent failure mode if the user expects the first block to be an argument to .blurk, which it isn't. 3c) Actually, despite the fact that I stated 3 in terms of precedence, as far as the parser is concerned 3 probably means that statement control things are parsed top down, and the bottom up expression parser simply stops when it hits an operator {...}. 4) Adverbs apply to the previous unparenthesized prefix, infix, or postfix operator, bypassing simple terms and other "pill" operators such as circumfix or postcircumfix. $a + $b :foo # applies to + $a + @b[2] :foo # applies to + $a + int($b) :foo # applies to int $a + (int($b)) :foo # applies to + @a.=sort:{ +$_ } # applies to .sort @a.sort(:quick):{ +$_ } # applies to .sort @a.sort:quick:{ +$_ } # both adverbs apply to .sort (This kind of argues that the iterator deref operator <...> shouldn't be a circumfix though, if we want to adverb it. It's tempting to steal <...> for something else anyway.) 5) The idea of trying to guess by lookahead heuristics whether methods have parameters is dead (except for parens and colon). The idea of using the colon in method C<.foo: 1,2,3> to force an unparenthesized argument list is also dead. The adverbs are more powerful, and more importantly, keep the operator precedence parser at the right precedence, and keep the parens off of attribute methods everywhere (except interpolation, of course). Plus the indirect-object-like use of colon was ambiguous with real indirect objects anyway: foo $bar.baz: 1,2,3 # now is unambiguously $bar.baz.foo(1,2,3) So the upshot is that if you want to avoid the parens around curlies ugliness: @foo.map({...}).sort({...}) you write the blocks as adverbs: @foo.map:{...}.sort:{...} Larry