A12: Mutating Methods and hyperoperators
I know these were discussed to death not that long ago, but reading Apocalypse 12 I had a query I couldn't remember if it had been covered before or not, and I certainly don't recall seeing it in the Apocalypse, although I've not read the entire thing with as much attention as I might like yet (it's great work though). So, simple query. I know I can do @things».method(); But can I do @things».=method(); which would presumably be the same as map { .=method() } @things; And if I can't do it, why not? I think I should be able to do it, but it's entirely possible I've missed something, because I usually have. Thanks Matthew
Re: A12: Mutating Methods and hyperoperators
Matthew Walton writes: I know these were discussed to death not that long ago, but reading Apocalypse 12 I had a query I couldn't remember if it had been covered before or not, and I certainly don't recall seeing it in the Apocalypse, although I've not read the entire thing with as much attention as I might like yet (it's great work though). So, simple query. I know I can do @things.method(); But can I do @things.=method(); Of course. which would presumably be the same as map { .=method() } @things; And if I can't do it, why not? I think I should be able to do it, but it's entirely possible I've missed something, because I usually have. Not this time :-) Luke
Re: A12: Mutating Methods and hyperoperators
Luke Palmer wrote: Matthew Walton writes: But can I do @things».=method(); Of course. Excellent. Thankyou. Not this time :-) Next time then, probably.
Re: Mutating methods
Larry Wall writes: Despite the severe overloading problems, it's really gonna be hard to do much better than $topic ? (.a + .b + .c) my dog $spot ?= .new; @array?.[.min .. .max] And I do think people would rebel at using Latin-1 for that one. I get enough grief for «...». :-) Larry How about - which is not overloaded by boolean connotations and is sort of ? turned by 90 degrees . $topic- (.a + .b + .c) my dog $spot- = .new @array- .[.min .. .max] arcadi
Re: Mutating methods
On Tue, Mar 16, 2004 at 08:40:50PM +0200, arcadi shehter wrote: : How about - which is not overloaded by boolean connotations : and is sort of ? turned by 90 degrees . Don't think so. It's too ambiguous with current meanings. : $topic- (.a + .b + .c) That asks if $topic is numerically less than the negated return value of the sum of ($_.a + $_.b + $_.c). : my dog $spot- = .new That's currently a syntax error. : @array- .[.min .. .max] That asks if the length of @array is less than the negated value of $_[$_.min .. $_.max]. Larry
Re: Mutating methods
On Sat, 13 Mar 2004 05.30, John Siracusa wrote: The only case that seems even remotely onerous is this one: my My::Big::Class::Name $obj = My::Big::Class::Name.new(); vs. my My::Big::Class::Name $obj .= new() There's also the related issue of in-place operations on some difficult-to-write lvalue: @{$coderef.(argument).{hashelem}} = sort @{$coderef.(argument).{hashelem}}; Did I get the text the same both times? What about maintaining that code? What about side effects on the subroutine I called there? Someone Damian-shaped will probably come in and point out how to prettify that using given, but it still wouldn't be as short as last week's $coderef.(argument).{hashelem}.self:sort(); -- Debbie Pickett http://www.csse.monash.edu.au/~debbiep [EMAIL PROTECTED]
RE: Mutating methods
This brings me to another idea I have.. although I have a feeling you guys have already thought of it. Instead of ... $x = $a + $b + $c + $d; How about ... $x = +«$a $b $c $d» The closest way to what you have written is this: $x = 0; $x »+=« ($a, $b, $c, $d); Or the slightly less attractive (IMHO) syntax invented recently: $x +=« ($a, $b, $c, $d); Of course, perl6 will have a built-in reduce function as well (RFC76): $x = reduce {$^a + $^b} $a, $b, $c, $d; ~ John Williams
Re: Mutating methods
On Fri, Mar 12, 2004 at 03:47:57AM -0500, Austin Hastings wrote: : -Original Message- : From: Larry Wall [mailto:[EMAIL PROTECTED] : On Thu, Mar 11, 2004 at 11:38:11AM +, Andy Wardley wrote: : : Larry Wall wrote: : : multi sub *scramble (String $s) returns String {...} : : [...] : : Or you can just call it directly as a function: : : scramble(hello) : : : : Can you also call scramble as a class method? : : : : class String is extended { : : method scramble { ..etc... } : : } : : : : String.scramble(hello) : : Not unless you write a class method that takes an extra argument. : Otherwise you're passing a class where it expects a string, and a : string where it expects nothing. However, much like in Perl 5 you : can always force which class's method to call with : : hello.String::scramble(); : : But it would work as a class multi, right? : : class String is extended { : multi scramble(String $s) {...} : } You probably have to decide whether that's a multi sub or a multi method, at least syntactically. Though it may not matter which you pick because... : hello.scramble(); : String::scramble(hello); # Way overspecified for a multi... For a single argument function, those probably come out to the same thing in the end. With more arguments you have to start distinguishing single dispatch from multiple dispatch. Larry
Re: Mutating methods
On Fri, Mar 12, 2004 at 05:32:33AM -0500, Austin Hastings wrote: : Boo, hiss. : : Two things: : : 1- I'd rather use inplace than self. What is this place thing? I want the object to do something to itself reflexively, which may or may not involve places... : 2- I'd rather it be AFTER, than BEFORE, the name, because : : method sort : method sort:inplace : : reads, and more importantly SORTS, better than : : method inplace:sort : method sort Well, that's a point that has some weight, but... : To wit: : : method :infix:=(Array, Array) returns Scalar : method :infix:==(Array, Array) returns Boolean : method :infix:!=(Array, Array) returns Boolean : method :infix:===(Array, Array) returns Boolean : method :infix:!==(Array, Array) returns Boolean : method :infix:x(Array) returns Array : method :infix:x:inplace(Array is rw) : : ### Note: How to handle [undef]? return-undef, or PHP-like push? : method :postfix:[](Array is rw, ?Scalar) returns Scalar : : ### Inplace-only? : method clear(Array is rw) returns Boolean : : method compact(Array) returns Array : method compact:inplace(Array is rw) : ### Inplace-only? : method delete(Array is rw, Int) returns WHAT, exactly? : : method difference(Array, Array) returns Array #A-B : method differences(Array, Array) returns Array #(A-B) + (B-A) : method exists(Array, Scalar) returns Boolean : method flatten(Array) returns Array : method flatten:inplace(Array is rw) returns Array : method grep(Array, Code) returns Array : method includes(Array, Scalar) returns Boolean : method index(Array, Scalar) returns Int : method intersect(Array, Array) : method is_empty(Array) return Boolean : method join(Array, String) : method length(Array) : method map(Array, Code) returns Array : method pack(Array, String) returns String : method reverse(Array) returns Array : method reverse:inplace(Array is rw) : method rindex(Array) returns Int : : ### Boy are these likely to be wrong! : method sort(Array, ?Code) returns Array : method sort:inplace(Array is rw, ?Code) : : ### Inplace-only? : method splice(Array is rw, ?Int, ?Int, ?Array) : : method union(Array, Array) returns Array : method unique(Array) returns Array : method unique:inplace(Array is rw) : : ### Inplace-only? : multi method fill(Array is rw, Scalar, Int, Int) : multi method fill(Array is rw, Scalar, Int) : multi method fill(Array is rw, Scalar, Array) : ### Inplace-only? : multi method pop(Array is rw, ?Int) returns Array : multi method pop(Array is rw) returns Scalar : ### Inplace-only? : multi method unshift(Array is rw, Scalar) returns Array : multi method unshift(Array is rw, Array) returns Array : ### Inplace-only? : multi method push(Array is rw, Array) returns Array : multi method push(Array is rw, Scalar) : ### Inplace-only? : multi method shift(Array is rw, Int) returns Array : multi method shift(Array is rw) returns Scalar : : multi sub each(Array) returns Iterator # HOW does this work? But you can put the declarations in whatever order you want regardless of the default collation order, so this is kind of a weak argument unless you're writing a tool, in which case you could certainly ignore whatever prefixes you like when you sort. : (Note also that :...fix sorts better than in-, post-, and pre-. I'd like to : suggest changing : them, since it costs nothing and results in a mild improvement in automation : behavior.) The main reason those are out front is to reduce grammatical ambiguity when you use an operator sub name where a term is expected. That is, it's harder to parse: $x = +:foo(); correctly than $x = foo:+(); Even with sort:inplace, how does the parser know that the name is sort:inplace, or whether the user is trying to pass a pair :inplace to the sort routine? The foo:-style prefixes are reserved in general, but the :foo pair is not, and it would be a mistake to start introducing reserved pairs, I think, much like the Perl 5 problem that ARGV is truly global while ARGH is not. : Another interesting question, if the postfix:.=foo mess is defined : with as self:foo, should infix:+= be defined as self:+ instead? : In other words, should the op= syntax really be a metasyntax like : hyperoperators, where you never actually have to define a C»+« : operator, but the hyperoperator is always autogenerated from ordinary : C+? So basically any infix:op= gets remapped to self:op. : : I think that would be cleaner. : : Alternatively, is there a valid reason to *need* to define your own : hyperoperator? : : That is, can you code C @a +« $x better than C @a.map {return $_ + $x} : ? I suspect that it's
Re: Mutating methods
- Original Message - From: Deborah Pickett [EMAIL PROTECTED] To: Perl 6 Language [EMAIL PROTECTED] Sent: Sunday, March 14, 2004 10:44 PM Subject: Re: Mutating methods On Sat, 13 Mar 2004 05.30, John Siracusa wrote: The only case that seems even remotely onerous is this one: my My::Big::Class::Name $obj = My::Big::Class::Name.new(); vs. my My::Big::Class::Name $obj .= new() There's also the related issue of in-place operations on some difficult-to-write lvalue: @{$coderef.(argument).{hashelem}} = sort @{$coderef.(argument).{hashelem}}; Did I get the text the same both times? What about maintaining that code? What about side effects on the subroutine I called there? Someone Damian-shaped will probably come in and point out how to prettify that using given, but it still wouldn't be as short as last week's $coderef.(argument).{hashelem}.self:sort(); Why not just do @{$_} = sort @{$_} given $coderef.(argument).{hashelem}; Joe Gottman
Re: Mutating methods
On Mon, Mar 15, 2004 at 08:36:23PM -0500, Joe Gottman wrote: : : - Original Message - : From: Deborah Pickett [EMAIL PROTECTED] : To: Perl 6 Language [EMAIL PROTECTED] : Sent: Sunday, March 14, 2004 10:44 PM : Subject: Re: Mutating methods : : : On Sat, 13 Mar 2004 05.30, John Siracusa wrote: : The only case that seems even : remotely onerous is this one: : : my My::Big::Class::Name $obj = My::Big::Class::Name.new(); : vs. : my My::Big::Class::Name $obj .= new() : : There's also the related issue of in-place operations on some : difficult-to-write lvalue: : : @{$coderef.(argument).{hashelem}} = :sort @{$coderef.(argument).{hashelem}}; : : Did I get the text the same both times? What about maintaining that code? : What about side effects on the subroutine I called there? : : Someone Damian-shaped will probably come in and point out how to prettify : that : using given, but it still wouldn't be as short as last week's : : $coderef.(argument).{hashelem}.self:sort(); : : :Why not just do : @{$_} = sort @{$_} given $coderef.(argument).{hashelem}; Er, let me guess. Because it still wouldn't be as short as last week's $coderef.(argument).{hashelem}.self:sort(); maybe? :-) My other guesses are: the end-weight problem, the forward reference on the multiple pronouns, the fact that you still need to recognize that the argument is the same as the result, or the general grottiness of @{$_} as a deref syntax compared to dot. Did I get it right? Larry
Re: Mutating methods
Date: Fri, 12 Mar 2004 12:01:10 -0800 Larry Wall wrote: It's really a pity that question mark is already so overloaded with boolean connotations, because $dog? .bark would really be the best postfix operator in ASCII for this. People would probably end up writing my Dog $spot ?= .new; as an idiom. And @array?[.min .. .max] would be the way to get a topicalized subscript. some time in the past there was a talk about ... ?? ... :: ... operator being a combination of two binary : ?? and :: . But I dont know the ruling. If one factorize trinary ??:: to two binary operators, ?? could act a postfix topicalazer while :: becomes binary operator : $a :: $b evaluates to left or right argument according to true/false property of the _current topic_ something like infix:::($a,$b){ given CALLER::_ { when .true return $a ; return $b } but it evaluate $b only if necessary. Arcadi
RE: Mutating methods
-Original Message- From: Larry Wall [mailto:[EMAIL PROTECTED] On Thu, Mar 11, 2004 at 11:38:11AM +, Andy Wardley wrote: : Larry Wall wrote: : multi sub *scramble (String $s) returns String {...} : [...] : Or you can just call it directly as a function: : scramble(hello) : : Can you also call scramble as a class method? : : class String is extended { : method scramble { ..etc... } : } : : String.scramble(hello) Not unless you write a class method that takes an extra argument. Otherwise you're passing a class where it expects a string, and a string where it expects nothing. However, much like in Perl 5 you can always force which class's method to call with hello.String::scramble(); But it would work as a class multi, right? class String is extended { multi scramble(String $s) {...} } hello.scramble(); String::scramble(hello); # Way overspecified for a multi... =Austin
RE: Mutating methods
-Original Message- From: Larry Wall [mailto:[EMAIL PROTECTED] On Thu, Mar 11, 2004 at 06:49:44AM -0800, Gregor N. Purdy wrote: : So, will mutatingness be a context we'll be able to inquire on : in the implementation of a called routine? Probably not, but it's vaguely possible you could somehow get a reference to what is being assigned to, if available, and check to see if $dest =:= $src (where =:= tests to see if two refs point to the same object). But in general I think most want testing is just a way of making code run slow, because it forces tests to be done at run time that should be done at compile time or dispatch time. It's better for the optimizer if you can give it enough type hints and signature hints to decide things earlier than the body of the sub or method. : Or, could we provide a specialized distinct implementation : for mutating that would get called if .=X() is used? That is much more likely. In general if you don't define both an op and an op= then Perl can autogenerate or emulate the missing one for you. Now in the specific case of . and .= we don't exactly have a normal binary operator, because the right side is not an expression. $tis.=««sad pity pity sad sad pity true»; $s .= ($useMbcs ? wlength : length); (Side note: although that expression isn't valid, since the wlength and length methods aren't qualified, it *should* be, since a human could infer it rather easily. Can we make that DWIM? (One way would be for the parser to convert that into if-else form if it appeared ambiguous.)) So we may have to provide a way of marking a normal method as a mutator. Possibly we end up with method =sort (Array @ary) returns Array {...} # inplace method sort (Array @ary) returns Array {...} # cloning That works nicely with the .= vs . distinction, visually speaking. Why not just put a property on the calling context, and allow either: # Run-time handling method sort(Array @a) { if ($CALLER.mutating) {...} ...} or # Properties should be after names method sort:mutating(Array @a) {...} or # But this is consistent with operators method mutating:sort(Array @a) {...} On the other hand, you might want to do the same with multi subs: multi sub =sort (Array @ary) returns Array {...} # inplace multi sub sort (Array @ary) returns Array {...} # cloning and then it gets a little more problematic syntactically because multis are called like subroutines: =sort(@array); We would have to allow an initial = at the beginning of a term. So far I've resisted doing that because I don't want @obj.meth=foo(); to become ambiguous, in case I decide to make the parentheses optional on method calls with arguments. If I did decide that, and we have terms beginning with =, it would not be clear whether the above meant @obj.meth(=foo()); or @obj.meth=(foo()); Or @obj.meth = foo(); (As much as I despise those who don't use spaces around the assignment operator, I'm willing to defend their right to the practice...) The = prefix notation also doesn't work very well for talking about the name of a routine: =sort That looks an awful lot like a junctive assignment operator... But it would be obvious from context that it was/n't: $foo = =sort; bar(=sort); $baz =sort; From a C++-ish perspective, the right thing to do is to differentiate not by the name but by the declared mutability of the invocant: multi sub sort (Array @ary is rw) returns Array {...} # inplace multi sub sort (Array @ary) returns Array {...} # cloning Or I suppose a case could be made for something that specifically declares you're returning one of the arguments: multi sub sort (Array @ary is rw) returns @ary {...} # inplace After all, it's possible to write a method that mutates its invocant but *doesn't* return it like a well-behaved mutator should. You don't always call a mutator in a void context--sometimes you want to be able to stack mutators: @array.=sort.=uniq; So you have to be able to return the mutant as well as mutate it in place. In the case of mutators, won't the return always be the first argument? So couldn't we just say: multi sub sort(Array @ary is rw is mutated) returns Array {...} multi sub sort(Array @ary) returns Array {...} (and can't we infer the returns Array when is mutated is provided?) On the other hand, I'm deeply suspicious of a return signature that mentions a specific variable. What if the body says to return something else? Is that just ignored? Do we check it to see if it's the same item? No. You might well say: $string.=length; And convert from one subtype to another. I think the mutation indicator is a hint to the optimizer, and a crutch for the implementor, in cases where it's possible to squeeze more performance out of skipping the assignment phase. (In particular, where an
Re: Mutating methods
On Fri, 12 Mar 2004 10.51, Damian Conway wrote: There are also cases where something like: $a ||= $b; or: $a += $b; changes the type of value in $a. Should we flag those too? Currently we do warn on the second one if $a can't be cleanly coerced to numeric. Would that be enough for Ccmp= too, perhaps? That triggered a thought about unary operators. What about: $a !=;# i.e., $a = ! $a; Obviously that particular example is a syntax error, but perhaps a more verbose self: version of same would not be. -- Debbie Pickett http://www.csse.monash.edu.au/~debbiep [EMAIL PROTECTED]
RE: Mutating methods
-Original Message- From: Damian Conway [mailto:[EMAIL PROTECTED] Larry wrote: On the other hand, I suspect most people will end up declaring it int method self:rotate (int $a is rw) {...} in any event, and reserve the =rotate for .=rotate, which can never put the = on the left margin, even if we let ourselves have whitespace before POD directives. So maybe we just require self: for the declaration, and forget about = there. Yes please! It interacts badly with global names anyway. Is it *=sort or =*sort? With *self:sort it's more obvious. Agreed. I'd *very* much prefer to see reflexive methods like this declared Cself:methodname. From a readability stand-point, if for no other reason. Boo, hiss. Two things: 1- I'd rather use inplace than self. 2- I'd rather it be AFTER, than BEFORE, the name, because method sort method sort:inplace reads, and more importantly SORTS, better than method inplace:sort method sort To wit: method :infix:=(Array, Array) returns Scalar method :infix:==(Array, Array) returns Boolean method :infix:!=(Array, Array) returns Boolean method :infix:===(Array, Array) returns Boolean method :infix:!==(Array, Array) returns Boolean method :infix:x(Array) returns Array method :infix:x:inplace(Array is rw) ### Note: How to handle [undef]? return-undef, or PHP-like push? method :postfix:[](Array is rw, ?Scalar) returns Scalar ### Inplace-only? method clear(Array is rw) returns Boolean method compact(Array) returns Array method compact:inplace(Array is rw) ### Inplace-only? method delete(Array is rw, Int) returns WHAT, exactly? method difference(Array, Array) returns Array #A-B method differences(Array, Array) returns Array #(A-B) + (B-A) method exists(Array, Scalar) returns Boolean method flatten(Array) returns Array method flatten:inplace(Array is rw) returns Array method grep(Array, Code) returns Array method includes(Array, Scalar) returns Boolean method index(Array, Scalar) returns Int method intersect(Array, Array) method is_empty(Array) return Boolean method join(Array, String) method length(Array) method map(Array, Code) returns Array method pack(Array, String) returns String method reverse(Array) returns Array method reverse:inplace(Array is rw) method rindex(Array) returns Int ### Boy are these likely to be wrong! method sort(Array, ?Code) returns Array method sort:inplace(Array is rw, ?Code) ### Inplace-only? method splice(Array is rw, ?Int, ?Int, ?Array) method union(Array, Array) returns Array method unique(Array) returns Array method unique:inplace(Array is rw) ### Inplace-only? multi method fill(Array is rw, Scalar, Int, Int) multi method fill(Array is rw, Scalar, Int) multi method fill(Array is rw, Scalar, Array) ### Inplace-only? multi method pop(Array is rw, ?Int) returns Array multi method pop(Array is rw) returns Scalar ### Inplace-only? multi method unshift(Array is rw, Scalar) returns Array multi method unshift(Array is rw, Array) returns Array ### Inplace-only? multi method push(Array is rw, Array) returns Array multi method push(Array is rw, Scalar) ### Inplace-only? multi method shift(Array is rw, Int) returns Array multi method shift(Array is rw) returns Scalar multi sub each(Array) returns Iterator # HOW does this work? (Note also that :...fix sorts better than in-, post-, and pre-. I'd like to suggest changing them, since it costs nothing and results in a mild improvement in automation behavior.) Another interesting question, if the postfix:.=foo mess is defined with as self:foo, should infix:+= be defined as self:+ instead? In other words, should the op= syntax really be a metasyntax like hyperoperators, where you never actually have to define a C»+« operator, but the hyperoperator is always autogenerated from ordinary C+? So basically any infix:op= gets remapped to self:op. I think that would be cleaner. Alternatively, is there a valid reason to *need* to define your own hyperoperator? That is, can you code C @a +« $x better than C @a.map {return $_ + $x} ? I suspect that it's possible to do so, particularly for such simple cases as assignment. (Hint: Persistent objects, database, one SQL statement per assignment.) So perhaps I should ask for an :infix:=« operator override? On the other hand, it also means that someone can say silly things like: $a cmp= $b $a ~~= $b I suppose we could simply disallow meta-= on non-associating operators. Can anyone come up with a
Re: Mutating methods
Austin Hastings writes: -Original Message- From: Larry Wall [mailto:[EMAIL PROTECTED] On Thu, Mar 11, 2004 at 06:49:44AM -0800, Gregor N. Purdy wrote: : So, will mutatingness be a context we'll be able to inquire on : in the implementation of a called routine? Probably not, but it's vaguely possible you could somehow get a reference to what is being assigned to, if available, and check to see if $dest =:= $src (where =:= tests to see if two refs point to the same object). But in general I think most want testing is just a way of making code run slow, because it forces tests to be done at run time that should be done at compile time or dispatch time. It's better for the optimizer if you can give it enough type hints and signature hints to decide things earlier than the body of the sub or method. : Or, could we provide a specialized distinct implementation : for mutating that would get called if .=X() is used? That is much more likely. In general if you don't define both an op and an op= then Perl can autogenerate or emulate the missing one for you. Now in the specific case of . and .= we don't exactly have a normal binary operator, because the right side is not an expression. $tis.=sad pity pity sad sad pity true; $s .= ($useMbcs ? wlength : length); (Side note: although that expression isn't valid, since the wlength and length methods aren't qualified, it *should* be, since a human could infer it rather easily. Well, for a slightly more complex expression, a human would have some trouble. This is very likely to be laziness, and we can do without it. There is certainly a way to do this if it is absolutely necessary: my $method = ($useMbcs ?? 'wlength' :: 'length'); $s.=$method; On the other hand, I'm deeply suspicious of a return signature that mentions a specific variable. What if the body says to return something else? Is that just ignored? Do we check it to see if it's the same item? No. You might well say: $string.=length; And convert from one subtype to another. I think the mutation indicator is a hint to the optimizer, and a crutch for the implementor, in cases where it's possible to squeeze more performance out of skipping the assignment phase. (In particular, where an inefficient assignment operator exists.) The last thing we need is another idiom that gets destroyed for efficiency reasons. Once people hear that that is fast, they'll start writing: $string.=length; Instead of what they would usually write, the much cleaner: my $len = $string.length; Even though the latter is only 0.05% slower. Speed has corrupted many programmers. Question: Can all this noise be eliminated by paying more attention to the construction of the assignment operator? That is, do we have an example where $a .= meth is going to perform poorly, and that performance is NOT because of the $a = $a.meth assignment? (And that cannot be fixed by declaring the invocant 'is rw'.) The performance issue is never because of the assignment. Assignment is basically free: it's just copying a pointer. It's usually because of the construction. Constructing a 10,000 element array's going to be expensive, so you'd rather sort in place. Luke
Re: Mutating methods
Larry Wall [EMAIL PROTECTED] wrote in message news:[EMAIL PROTECTED] Unfortunately we can't just use topicalization to say my Cat $tom = .new() because most people won't expect simple assignment to break their current topic. So another option is to replace = with something that Idoes set the topic for the right side. If we used .= for that, then you'd have to write [...] Another approach would be to have some kind of microtopic that represented the left side of an ordinary assignment. Suppose for the sake of argument that the microtopic is ^. Then you could write @array = ^.sort; and a constructor would be my Kanga $roo = ^.new() But that introduces a new concept that doesn't really generalize well. So forget that. Why are we mixing the concepts of assignment and topicalization -- especially in a way that doesn't generalize. Why can't we invent a topicalization operator, analogous to the old binding operator, that simply sets its LHS as the topic of its RHS: and then have an assigning version of that operator. For example, lets use the section Unicode symbol: § to locally set the current topic within an expression. Now we could say: $x = ( $foo § .a + .b + .c ) to mean $x = $foo.a + $foo.b + $foo.c The assigning version of the operator could be $x §= .foo; my Dog $dog §= .new; Dave.
Re: Mutating methods
On Fri, Mar 12, 2004 at 03:47:22AM -0500, Austin Hastings wrote: -Original Message- From: Larry Wall [mailto:[EMAIL PROTECTED] Now in the specific case of . and .= we don't exactly have a normal binary operator, because the right side is not an expression. $tis.=««sad pity pity sad sad pity true»; $s .= ($useMbcs ? wlength : length); (Side note: although that expression isn't valid, since the wlength and length methods aren't qualified, it *should* be, since a human could infer it rather easily. Can we make that DWIM? (One way would be for the parser to convert that into if-else form if it appeared ambiguous.)) So ... how smart will perl6 be? $o .= (foo,bar,baz); $o .= (expr_returning_method); Since human expectations vary I don't think I want these. -Scott -- Jonathan Scott Duff [EMAIL PROTECTED]
Re: Mutating methods
On Fri, Mar 12, 2004 at 12:29:36PM +1100, Deborah Pickett wrote: : That triggered a thought about unary operators. What about: : : $a !=;# i.e., $a = ! $a; Well, an argument could be made that the corresponding syntax is really: != $a; But you have to read the A op= B == A = A op B transformation differently. Something more like A op= B == mysterylocation = A op B where mysterylocation turns out to be the first actual term, which when A is specified is A, and otherwise B. In other words, dropping the A out gives you both the binary and unary forms: A op= B == mysterylocation = A op B op= B == mysterylocation = op B That could actually be pretty handy for += $a # coerce yourself to numeric ~= $a # coerce yourself to string ?= $a # coerce yourself to boolean On the other hand, if we did that generally, we'd also get operators like: \= $a # turn $a into a reference to itself Yow. : Obviously that particular example is a syntax error, but perhaps a more : verbose self: version of same would not be. Well, it's only a syntax error because we say it's a syntax error. But I do think prefix unarys tend to be more readable than postfix. But, yes, method calls are essentially unary postfix operators. In the OO worldview it's perfectly valid to tell an object to do something to itself. In the functional worldview, of course, keeping any kind of state is viewed with deep suspicion. So really, it's just a matter of whether there's a standard syntax for negate yourself. I don't think there is a large call for it, since most objects don't think of themselves as booleans. But if an object did want to support that behavior, saying $a.self:!(); would certainly be self evident, as it were. It might even come for free with the Boolean role. But then there's the good question of whether to allow the unary op: != $a; Some good questions only have bad answers. This might be one of them. Larry
Re: Mutating methods
Larry Wall wrote: Now, if we had a unary = that assigned to the current topic, we could do it with the existing topicalizer as given my Dog $dog { = .new } But I'm not recommending that approach, because I dislike unary =, and because I don't want every declaration to have to say given. my Dog $dog given= .new; Where 'given' is 'wa'. Unfortunately, it's backwards compared to the statement modifiers Perl already has. That suggests =.new given my Dog $dog; but that requires the unary equals you apparently don't like *and* puts the less important bit on the LHS. Bah. Just use 'wa' and make the world learn Japanese. :^P -- Brent Dax Royal-Gordon [EMAIL PROTECTED] Perl and Parrot hacker Oceania has always been at war with Eastasia.
Re: Mutating methods
Oh, it's got lots of Japanese in it, I'd better read it... :) [EMAIL PROTECTED] (Larry Wall) writes: Some will argue that since English doesn't have a grammatical postfix topicalizer like Japanese, we should stick with something like more English-like: $x = (.a + .b + .c given $foo) I think I'm missing something here. We have given as a perfectly good topicaliser. Now, I remember harping on a while ago about generalizing the idea of some control structures returning values, such as $x = if $a { $b } else { $c }; Now if we do generalise that, we get $x = given $foo { .a + .b + .c }; which gives us the topic-in-front form, the given which is the standard way of declaring the topic, and it's all nice. my Dog $dog wa= .new; Urgh. This reads like you're topicalising a $dog, assigning to it and acting on it all at the same time. Too many particles! my Dog $inu wa ga o new desu; # ? :) So you could usefully say something like $modthingie wa %= .modulus; Hrm. given($modthingie) %= .modulus; might work, but it relies on a few pieces of underlying magic, none of which I believe to be over-the-top in themselves but taken together may leave a bad taste: control structures return a value, as above given takes an optional block, purely setting the topic if no block the topic persists throughout a statement if operator it is. I don't think it's an operator so much as a function. It sets the topic and, depending on how things turn out, returns either void or the topic again. -- teco /dev/audio - Ignatios Souvatzis
Re: Mutating methods
Larry Wall wrote: multi sub *scramble (String $s) returns String {...} [...] Or you can just call it directly as a function: scramble(hello) Can you also call scramble as a class method? class String is extended { method scramble { ..etc... } } String.scramble(hello) A
Re: Mutating methods
Larry Wall wrote: Yet another approach is to *replace* dot with something that mutates: @array!sort @array?sort Either of those would work syntactically in that case, since neither ! nor ? is expected as a binary operator. What about ? is as a ternary operator: @foo?bar:baz; Or am I missing.something? A
Re: Mutating methods
AW == Andy Wardley [EMAIL PROTECTED] writes: AW What about ? is as a ternary operator: AW @foo?bar:baz; IIRC, that was changed to ?? :: because larry wanted the single ? for more important uses. also doubling the ? made it more like , || which are related logical ops. and ?? as the oneshot regex match is totally out. uri -- Uri Guttman -- [EMAIL PROTECTED] http://www.stemsystems.com --Perl Consulting, Stem Development, Systems Architecture, Design and Coding- Search or Offer Perl Jobs http://jobs.perl.org
Re: Mutating methods
Larry -- So, will mutatingness be a context we'll be able to inquire on in the implementation of a called routine? Or, could we provide a specialized distinct implementation for mutating that would get called if .=X() is used? If we are performing some operation on large data, and we know the end result is going to clobber the current object, we could avoid making an extra copy. I suppose there is some danger here. What if I write a class that I intend to have value semantics. That is, once an instance's value is set at construction time, it never changes, although you can get new instances by invoking its methods. BigInt would work this way. I can imagine a Point class working this way - you don't (necessarily) want two objects hanging on to a point, and one of them to mutate it into a different value out from under the other one. You wouldn't expect that behavior from other value objects such as built-in strings. This points at mutatingness being aimed at the reference (variable) not the referrent (value), unless it can be different in the case of value-objects and container-objects... So, if we had a BigDataContainer class for which it *was* reasonable to mutate it in place, and we wanted that behavior to trigger on .= to do an in-place modification: $bigData .=applyBlockCipher($cipher, $key); would there be a way to do that without the extra copy implied in: $bigData = $bigData.applyBlockCipher($cipher, $key); while leaving $foo .=someOtherMethod(); equivalent to $foo = $foo.someOtherMethod(); when $foo's class or someOtherMethod() implementation doesn't do anything special? Regards, -- Gregor On Wed, 2004-03-10 at 21:29, Larry Wall wrote: On Wed, Mar 10, 2004 at 10:46:05PM -0500, matt wrote: : I was thinking along the lines of... : : String $foo = hello; : $foo.scramble! That would be $foo.=scramble in the current scheme of things. : print $foo\n; : $foo = hello : print $foo.scramble ~ \n; : print $foo; : : OUTPUT (or close): : elhlo : hloel : hello : : Also, along these same things.. is there a way to apply a method to all : variables/objects of a certain type (e.g. String, Num, etc)? Taking the : above example.. being able to write a method called Scramble that can be : called as a method from any String type. Two ways, actually. You can 'reopen the String class and add the method: class String is extended { method scramble () returns String {...} } or if you consider that underhanded, you can define a multi-sub: multi sub *scramble (String $s) returns String {...} If you call that as a method, and there is no ordinary scramble method, it will fail soft to looking for a scramble multimethod, and end up calling your definition. Or you can just call it directly as a function: scramble(hello) Larry -- Gregor Purdy[EMAIL PROTECTED] Focus Research, Inc. http://www.focusresearch.com/
Re: Mutating methods
On Thu, Mar 11, 2004 at 11:38:11AM +, Andy Wardley wrote: : Larry Wall wrote: : multi sub *scramble (String $s) returns String {...} : [...] : Or you can just call it directly as a function: : scramble(hello) : : Can you also call scramble as a class method? : : class String is extended { : method scramble { ..etc... } : } : : String.scramble(hello) Not unless you write a class method that takes an extra argument. Otherwise you're passing a class where it expects a string, and a string where it expects nothing. However, much like in Perl 5 you can always force which class's method to call with hello.String::scramble(); Larry
Re: Mutating methods
On Thu, Mar 11, 2004 at 06:49:44AM -0800, Gregor N. Purdy wrote: : So, will mutatingness be a context we'll be able to inquire on : in the implementation of a called routine? Probably not, but it's vaguely possible you could somehow get a reference to what is being assigned to, if available, and check to see if $dest =:= $src (where =:= tests to see if two refs point to the same object). But in general I think most want testing is just a way of making code run slow, because it forces tests to be done at run time that should be done at compile time or dispatch time. It's better for the optimizer if you can give it enough type hints and signature hints to decide things earlier than the body of the sub or method. : Or, could we provide a specialized distinct implementation : for mutating that would get called if .=X() is used? That is much more likely. In general if you don't define both an op and an op= then Perl can autogenerate or emulate the missing one for you. Now in the specific case of . and .= we don't exactly have a normal binary operator, because the right side is not an expression. So we may have to provide a way of marking a normal method as a mutator. Possibly we end up with method =sort (Array @ary) returns Array {...} # inplace method sort (Array @ary) returns Array {...} # cloning That works nicely with the .= vs . distinction, visually speaking. On the other hand, you might want to do the same with multi subs: multi sub =sort (Array @ary) returns Array {...} # inplace multi sub sort (Array @ary) returns Array {...} # cloning and then it gets a little more problematic syntactically because multis are called like subroutines: =sort(@array); We would have to allow an initial = at the beginning of a term. So far I've resisted doing that because I don't want @obj.meth=foo(); to become ambiguous, in case I decide to make the parentheses optional on method calls with arguments. If I did decide that, and we have terms beginning with =, it would not be clear whether the above meant @obj.meth(=foo()); or @obj.meth=(foo()); The = prefix notation also doesn't work very well for talking about the name of a routine: =sort That looks an awful lot like a junctive assignment operator... From a C++-ish perspective, the right thing to do is to differentiate not by the name but by the declared mutability of the invocant: multi sub sort (Array @ary is rw) returns Array {...} # inplace multi sub sort (Array @ary) returns Array {...} # cloning Or I suppose a case could be made for something that specifically declares you're returning one of the arguments: multi sub sort (Array @ary is rw) returns @ary {...} # inplace After all, it's possible to write a method that mutates its invocant but *doesn't* return it like a well-behaved mutator should. You don't always call a mutator in a void context--sometimes you want to be able to stack mutators: @array.=sort.=uniq; So you have to be able to return the mutant as well as mutate it in place. On the other hand, I'm deeply suspicious of a return signature that mentions a specific variable. What if the body says to return something else? Is that just ignored? Do we check it to see if it's the same item? So my guess is that it's probably better to have something more specific for the mutator template. I think, actually, that I've convinced myself that a mutator should be marked in its name, and that it should generally be defined as a standard method rather than a multi sub: method =sort (Array @ary is rw) {...} # inplace This would automatically arrange to return the invocant. It would be illegal to use Creturn in such a routine. And I guess, since it's an ordinary method, we can leave out the invocant: method =sort () {...} # inplace with the assumption that the default invocant on a mutator would automatically be assumed rw. If you do happen to want to define a multi sub mutator, then the syntax for calling it could be «=sort»(@array) However, we really don't have to special case the = prefix syntax if we make it something like: methodpostfix:.=sort () {...} # inplace multi sub postfix:.=sort () {...} # inplace That's getting way up there on the ugliness factor. Might be worth a new operator category: methodmutate:sort () {...} # inplace multi sub mutate:sort () {...} # inplace or methodinplace:sort () {...} # inplace multi sub inplace:sort () {...} # inplace or methodrw:sort () {...} # inplace multi sub rw:sort () {...} # inplace or methodself:sort () {...} # inplace multi sub self:sort () {...} # inplace On the final hand, if people fall in love with both self:sort and =sort, we could have =sort be a shorthand for self:sort where it's unambiguous. On the (n+1)st hand, that says we could write it either as @array.=sort.=uniq or
Re: Mutating methods
On Thu, Mar 11, 2004 at 11:11:54AM -0800, Larry Wall wrote: On the final hand, if people fall in love with both self:sort and =sort, we could have =sort be a shorthand for self:sort where it's unambiguous. Wouldn't =sort potentially muck with POD? -Scott -- Jonathan Scott Duff [EMAIL PROTECTED]
Re: Mutating methods
On Thu, Mar 11, 2004 at 02:05:55PM -0600, Jonathan Scott Duff wrote: : On Thu, Mar 11, 2004 at 11:11:54AM -0800, Larry Wall wrote: : On the final hand, if people fall in love with both self:sort and =sort, we : could have =sort be a shorthand for self:sort where it's unambiguous. : : Wouldn't =sort potentially muck with POD? Could. Historically pod only pays attention to = on the left margin though. So you generally wouldn't have any problem unless you were in the habit of declaring your methods in the C-ish idiom of: int method =rotate (int $a is rw) {...} On the other hand, I suspect most people will end up declaring it int method self:rotate (int $a is rw) {...} in any event, and reserve the =rotate for .=rotate, which can never put the = on the left margin, even if we let ourselves have whitespace before POD directives. So maybe we just require self: for the declaration, and forget about = there. It interacts badly with global names anyway. Is it *=sort or =*sort? With *self:sort it's more obvious. Another interesting question, if the postfix:.=foo mess is defined with as self:foo, should infix:+= be defined as self:+ instead? In other words, should the op= syntax really be a metasyntax like hyperoperators, where you never actually have to define a C»+« operator, but the hyperoperator is always autogenerated from ordinary C+? So basically any infix:op= gets remapped to self:op. In that case, C»+=« is a double-meta operator that ends up generating a hyper self:+. I kinda like this approach because it means you can always get all of $a !! $b $a !!= $b @a »!!« @b @a »!!=« @b merely by defining infix:!!. On the other hand, it also means that someone can say silly things like: $a cmp= $b $a ~~= $b I suppose we could simply disallow meta-= on non-associating operators. Can anyone come up with a non-associating binary operator that *should* have an assignment operator? The basic definition of non-associating seems to be that the type of the arguments is incompatible with the type produced by the operator. Which is precisely the problem with something like $a cmp= $b insofar as $a is being treated as a string at one moment and as a boolean at the next. Larry
Re: Mutating methods
On Thu, Mar 11, 2004 at 12:43:22PM -0800, Larry Wall wrote: : Which is precisely the problem with something like : : $a cmp= $b : : insofar as $a is being treated as a string at one moment and as a boolean : at the next. Well, okay, not a boolean. More like a troolean. Larry
Re: Mutating methods
On 3/11/04 4:04 PM, Larry Wall wrote: On Thu, Mar 11, 2004 at 12:43:22PM -0800, Larry Wall wrote: : Which is precisely the problem with something like : : $a cmp= $b : : insofar as $a is being treated as a string at one moment and as a boolean : at the next. Well, okay, not a boolean. More like a troolean. Back in my daaa, we used to call that a scalar. And we liked it, because it was all we had! ;) -John
Re: Mutating methods
On Thu, 2004-03-11 at 13:04, Larry Wall wrote: Well, okay, not a boolean. More like a troolean. Unless it's a falselean. -- c
Re: Mutating methods
On Thu, Mar 11, 2004 at 01:18:52PM -0800, chromatic wrote: : On Thu, 2004-03-11 at 13:04, Larry Wall wrote: : : Well, okay, not a boolean. More like a troolean. : : Unless it's a falselean. It's more truelean than falselean by a 2/3rds majority. And it's much more if you include 2, -2, 3, -3,... in the data type. And it's *very* much more if you include the reals Larry
Re: Mutating methods
Larry Wall wrote: On Thu, Mar 11, 2004 at 01:18:52PM -0800, chromatic wrote: : On Thu, 2004-03-11 at 13:04, Larry Wall wrote: : : Well, okay, not a boolean. More like a troolean. : : Unless it's a falselean. It's more truelean than falselean by a 2/3rds majority. And it's much more if you include 2, -2, 3, -3,... in the data type. And it's *very* much more if you include the reals So that's a (numeric) scalar then... I'm new to this list, although I've been keeping an eye on Perl 6 for quite a while now as it's looking like it's going to be an extremely pleasant language to work with. Seems I joined at the right time as well, for these mutators are an interesting thing. Please excuse my no doubt numerous abuses of conventional formatting used here as I don't know it yet, and I've got a very shaky knowledge of some parts of the Perl 6 grammar that everyone posting seems to know. However, it strikes me that notation like int method =foo(String $bar) {...} is at risk of causing serious confusion to people coming from other languages. This may not be a concern, of course (and isn't really one of mine despite being a C++/Perl 5/Haskell kind of person at the moment). It seems that int method self:foo(String $bar) {...} is clearer and easier to read, but I did actually prefer int method mutate:foo(String $bar) {...} or int method inplace:foo(String $bar) {...} which seem to have been dismissed in favour of the form using Cself, although I can see that it does have a valid interpretation. Perhaps I'm just too stuck in writing member subs of objects in Perl 5 by saying sub foo { my $self = shift; # something useful here } so I always see 'self' as reading something like 'this' does in C++ or Java (or as 'self' does in Python, if I'm remembering that correctly). There is undeniable logic in using it to define mutators though, as they do most certainly act upon 'self' or 'this' or whatever it's called. One is lead to wonder if the most appropriate definition might not be int method mutator:foo(String $bar) { ... } but that's getting very silly, so maybe just ignore everything I said just now and cheer the introduction of Cself as the most practical and least prone to the introduction of finger trouble. And having said all that, I like .= as invocation syntax for it, even if I keep thinking it means 'append string'. Anyway, thankyou for listening, I shall return now to watching in awe. Matthew
Re: Mutating methods
Larry wrote: On the other hand, I suspect most people will end up declaring it int method self:rotate (int $a is rw) {...} in any event, and reserve the =rotate for .=rotate, which can never put the = on the left margin, even if we let ourselves have whitespace before POD directives. So maybe we just require self: for the declaration, and forget about = there. Yes please! It interacts badly with global names anyway. Is it *=sort or =*sort? With *self:sort it's more obvious. Agreed. I'd *very* much prefer to see reflexive methods like this declared Cself:methodname. From a readability stand-point, if for no other reason. Another interesting question, if the postfix:.=foo mess is defined with as self:foo, should infix:+= be defined as self:+ instead? In other words, should the op= syntax really be a metasyntax like hyperoperators, where you never actually have to define a C»+« operator, but the hyperoperator is always autogenerated from ordinary C+? So basically any infix:op= gets remapped to self:op. I think that would be cleaner. On the other hand, it also means that someone can say silly things like: $a cmp= $b $a ~~= $b I suppose we could simply disallow meta-= on non-associating operators. Can anyone come up with a non-associating binary operator that *should* have an assignment operator? The basic definition of non-associating seems to be that the type of the arguments is incompatible with the type produced by the operator. Which is precisely the problem with something like $a cmp= $b insofar as $a is being treated as a string at one moment and as a boolean at the next. I think it's merely a philosophical problem. After all, we don't complain when people write: $a = $a cmp $b; So should we complain when people write exactly the same thing, only as: $a cmp= $b; Stylistically, they're equally as abhorrent, but Perl users aren't expecting the Stylish Inquisition. The real question is whether the two forms are equally likely to indicate a logic error. One could argue that anyone who writes the first is more likely just being (small-l) lazy, whereas writing the second probably indicates a thinko. But then one could also argue that it's (small-l) lazier to write the second than the first, so the second is actually *more* likely to be (small-l) laziness than error. There are also cases where something like: $a ||= $b; or: $a += $b; changes the type of value in $a. Should we flag those too? Currently we do warn on the second one if $a can't be cleanly coerced to numeric. Would that be enough for Ccmp= too, perhaps? Damian
Mutating methods
Perlists, In Perl 5, lc, lcfirst, quotemeta, uc and ucfirst don't mutate. chomp and chop do mutate. I imagine these will all be methods in Perl 6: $foo.lc $foo.quotemeta $foo.chomp I'd like a mutating version of lc, and a non-mutating version of chomp. With some nice syntax, if possible. If there isn't already such a thing in the making, I hereby suggest to re-introduce C.=, to mean more or less the same as in Perl 5, but with Perl 6's version of the C. operator. In other words: C$foo.lc would not mutate and C$foo.=lc would. $foo += 5 === $foo = $foo + 5 $foo.=lc === $foo = $foo.lc Makes sense to me. Especially for Csort it would be nice for something like this: @foo.sort # returns sorted copy versus @foo.=sort # sorts inline I think this syntax reads better than Ruby's exclamation point (foo.method!), because of the analogy with other mutating operators. Please excuse me if this or something like this has already been taken care of - I've searched for messages about it, but haven't found anything. Regards, Juerd
Re: Mutating methods
Juerd writes: Perlists, In Perl 5, lc, lcfirst, quotemeta, uc and ucfirst don't mutate. chomp and chop do mutate. I imagine these will all be methods in Perl 6: $foo.lc $foo.quotemeta $foo.chomp I'd like a mutating version of lc, and a non-mutating version of chomp. With some nice syntax, if possible. If there isn't already such a thing in the making, I hereby suggest to re-introduce C.=, to mean more or less the same as in Perl 5, but with Perl 6's version of the C. operator. I believe this has been discussed before, and that people generally liked it. Maybe Larry even did (I seem to recall him saying something positive about it -- but don't think he did just because I said so :-). It seems likely that this will go in, though. I'm in the mood for an exercise, so, here's how you implement it. Let's say we have the Perl grammar: grammar Perl { # ... has %.assignment_ops is protected; rule assignment_expression { assignment_lhs $op:= (%.assignment_ops.keys()) $value := %.assignment_ops{$op}{rule} { $0 := %.assignment_ops{$op}{transform}($0) if %.assignment_ops{$op}{transform} } } rule method_call { term '.' method_name } } Or something. I'm just pulling that out of my ear. Then we'll derive our own grammar with the C.= operator in, and plunk it into Perl's parser. grammar DotEqualsPerl is Perl { submethod BUILD() { .assignment_ops{'.='} = { rule = /method_name/, transform = { Perl::assignment_expression.new( lhs = .{assignment_lhs}, rhs = Perl::method_call.new( term = .{assignment_lhs}, method = .{value}, ) ) }, }; } } Finally, hooking it into Perl. use grammar DotEqualsPerl; Again, this is quite presumptuous about the workings of the Perl::* classes. The Perl grammar will have to be extremely well documented. The reason we couldn't just decalre it with Cinfix:.= is because its right hand side is not a usual expression. That is: $foo + bar; Won't parse unless Cbar is a declared sub, whereas: $foo.bar; Will always parse. Luke
Re: Mutating methods
Luke Palmer wrote: The reason we couldn't just decalre it with Cinfix:.= is because its right hand side is not a usual expression. Isn't that what macros are for? macro infix:.= ($lhs, $rhs) is parsed(/method_name/) { return Perl::assignment_expression.new( lhs = $lhs, rhs = Perl::method_call.new( term = $lhs, method = $rhs, ) ); } TMTOWTDI, I suppose... -- Brent Dax Royal-Gordon [EMAIL PROTECTED] Perl and Parrot hacker Oceania has always been at war with Eastasia.
Re: Mutating methods
On Wed, Mar 10, 2004 at 05:39:33PM +0100, Juerd wrote: : Perlists, : : In Perl 5, lc, lcfirst, quotemeta, uc and ucfirst don't mutate. : chomp and chop do mutate. : : I imagine these will all be methods in Perl 6: : : $foo.lc : $foo.quotemeta : $foo.chomp : : I'd like a mutating version of lc, and a non-mutating version of chomp. : With some nice syntax, if possible. : : If there isn't already such a thing in the making, I hereby suggest to : re-introduce C.=, to mean more or less the same as in Perl 5, but with : Perl 6's version of the C. operator. Except that C. isn't really a binary operator... On the other hand, draft -1 of A12 has a conjectural my Dog $dog .= new() in it, and that's even further out there, since the .new on the right would in fact be called on a $dog that is undefined! : In other words: C$foo.lc would not mutate and C$foo.=lc would. : : $foo += 5 === $foo = $foo + 5 : $foo.=lc === $foo = $foo.lc : : Makes sense to me. Yes, but the fact that you had to change the spacing bothers me. : Especially for Csort it would be nice for something like this: : : @foo.sort # returns sorted copy : : versus : : @foo.=sort # sorts inline : : I think this syntax reads better than Ruby's exclamation point : (foo.method!), because of the analogy with other mutating operators. Well, I'd like to reserve postfix:! for factorial in any event. :-) The basic problem with .= shows up when you do put the spaces in: @foo .= sort() That makes it look as though sort is a subroutine, and it's not. That's a direct result of the fact that C. is not really a binary operator. Rather, it's a kind of operator sigil that introduces a unary postfix operator. Method calls are really unary postfix operators that happen to be able to take extra arguments. And because the op= syntax is really built for binary operators, it doesn't totally work for unary operators. Take another unary postfix operator, for instance, an array subscript: @array[$x] you can't just up and say @array[=$x] to mean @array = @array[$x] to turn it into a mutating operator, because the [$x] wants to function as a unit, and the = breaks that up. Similarly, .sort wants to function as a unit, but the = breaks that up, visually and semantically. However, having said all that, it turns out that A12 will also introduce other dot variants: $obj.?method# call method if exists, or return undef (0 or 1) $obj.*method# call all base class methods of that name (0 or more) $obj.+method# call all base class methods of that name (1 or more) So a .=method syntax is not so farfetched. It analogies to +=, but it's really still just a prefix to a unary postfix operator, like the other dot variants. The interesting question with all of these dots is where spaces are allowed or disallowed. One could make a case that people will want to write my Car $obj .= new() rather than being forced to write my Car $obj .=new() It could even be argued that, in the case of this particular operator, the = is functioning as part of the name, as the ! does in Ruby. So if (hypothetically) we allow a space after the ordinary dot @array . sort then we could also allow things like: @array . =sort $obj . *initialize $obj . ?maybe But I dislike $variable . meth() for the same reason I dislike $variable .= meth() because it makes meth look like a subroutine call when it isn't. Regardless of how fancy they get, method calls are still postfix operators. So I'm inclined to say that the space is only optional before the dot, and you have to say @array .sort @array .=sort $obj .*initialize $obj .?maybe But that still makes my Cat $tom .=new() pretty ugly. Unfortunately we can't just use topicalization to say my Cat $tom = .new() because most people won't expect simple assignment to break their current topic. So another option is to replace = with something that Idoes set the topic for the right side. If we used .= for that, then you'd have to write @array .= .sort my Cat $tom .= .new() Doubtless the first would get shortened to @array.=.sort That does admit to constructs like $foo .= .*bar which would assign $foo a list of all the return values of $foo.*bar, or $foo .= .?maybe which would presumably replace $foo with an undefined value if it couldn't find $foo.maybe. Those don't seem terribly useful as mutators though. They'd be much clearer written out long. Another approach would be to have some kind of microtopic that represented the left side of an ordinary assignment. Suppose for the sake of argument that the microtopic is ^. Then you could write @array = ^.sort; and a constructor would be my Kanga $roo = ^.new() But that introduces a new concept that doesn't really generalize well. So forget that. Yet another approach is to *replace* dot
Re: Mutating methods
On Wed, Mar 10, 2004 at 11:19:52AM -0800, Brent Dax Royal-Gordon wrote: : Luke Palmer wrote: : The reason we couldn't just decalre it with Cinfix:.= is because its : right hand side is not a usual expression. : : Isn't that what macros are for? : : macro infix:.= ($lhs, $rhs) is parsed(/method_name/) { Methods are really postfix operators, so that would probably be something more like: macro postfix:.= ($lhs, $parsetree) is parsed(/ws? ?method_name ?method_args/) { That's presuming we allow whitespace after the . and .= ops. (Also, these days you have to say ?foo to collect the results into $0.) Larry
Re: Mutating methods
Larry Wall writes: On Wed, Mar 10, 2004 at 11:19:52AM -0800, Brent Dax Royal-Gordon wrote: : Luke Palmer wrote: : The reason we couldn't just decalre it with Cinfix:.= is because its : right hand side is not a usual expression. : : Isn't that what macros are for? : : macro infix:.= ($lhs, $rhs) is parsed(/method_name/) { Methods are really postfix operators, so that would probably be something more like: macro postfix:.= ($lhs, $parsetree) is parsed(/ws? ?method_name ?method_args/) { That's presuming we allow whitespace after the . and .= ops. (Also, these days you have to say ?foo to collect the results into $0.) Hooray! That was something I had been worried about. But C? doesn't seem to fit visually. What's questionable about that? I can think of a couple that I like better: ^foo *foo ^foo is my favorite at the moment (even though *foo is more visually pleasing), because it looks like it's transferring the information ^up^ in the parse tree. Luke
Re: Mutating methods
Luke Palmer wrote: Hooray! That was something I had been worried about. But C? doesn't seem to fit visually. What's questionable about that? Nothing questionable, but everything hypothetical: ?foo captures to the $?foo hypothetical variable Damian
Re: Mutating methods
On Wed, Mar 10, 2004 at 12:42:00PM -0700, Luke Palmer wrote: : (Also, these days you have to say ?foo to collect the results into $0.) : : Hooray! That was something I had been worried about. : : But C? doesn't seem to fit visually. What's questionable about : that? It's questionable insofar as it's hypothetical. It maps to $?foo, which is the name of the (current value of the) capture within any interior closure: /?foo { say Guessing $?foo for the moment... bar } / : I can think of a couple that I like better: : : ^foo : *foo : : ^foo is my favorite at the moment (even though *foo is more : visually pleasing), because it looks like it's transferring the : information ^up^ in the parse tree. But $^foo and $*foo mean very different things from hypotheticals. And in a real sense $?foo is passing guessed information *down* the match. The guesses only turn out right if you get all the way to the bottom successfully. (That's from the point of view that you recurse deeper to check anything to the right in a regex, even when syntactically it's shallower.) Larry
Re: Mutating methods
Larry Wall writes: On Wed, Mar 10, 2004 at 12:42:00PM -0700, Luke Palmer wrote: : I can think of a couple that I like better: : : ^foo : *foo : : ^foo is my favorite at the moment (even though *foo is more : visually pleasing), because it looks like it's transferring the : information ^up^ in the parse tree. But $^foo and $*foo mean very different things from hypotheticals. And in a real sense $?foo is passing guessed information *down* the match. The guesses only turn out right if you get all the way to the bottom successfully. (That's from the point of view that you recurse deeper to check anything to the right in a regex, even when syntactically it's shallower.) Hmm... that makes sense. It doesn't feel right, though. After all, we don't say: ($minutes, $seconds) = m/ (? \d\d ) : (? \d\d ) /; Even though they only stay matched if they get to the end without backtracking. Capturing (this is really just a clever notation for captures) is usually about communicating information Ioutside of the match: to the parent rule, to the the calling scope. As you showed in your reply about C.=: macro postfix:.= ($lhs, $parsetree) is parsed(/ws? ?method_name ?method_args/) { ... } There's nothing about C? that makes me think that these are being stored. I understand the association with C$?foo. But most of the time, when I'm writing a grammar, I'm catching these rules in order to stick them in the parse tree, not to do tests on them later on in the rule. The very essence of rules is hypotheticality, where nothing is permanent until it gets to the end. I don't think we need a special marker that says these do that, too. Luke
Re: Mutating methods
Luke Palmer wrote: I understand the association with C$?foo. But most of the time, when I'm writing a grammar, I'm catching these rules in order to stick them in the parse tree, not to do tests on them later on in the rule. The very essence of rules is hypotheticality, where nothing is permanent until it gets to the end. I don't think we need a special marker that says these do that, too. We need the marker to distinguish between hypothetical captures to internal variables: / $?foo:=(abc) $?bar:=(def) / and non-hypothetical captures to external variable: / $foo:=(abc) $bar:=(def) / And since subrules that capture always capture to hypotheticals, we need the same marker there. Damian
Re: Mutating methods
Damian Conway wrote: / $foo:=(abc) $bar:=(def) / Am I misreading, or are you suggesting that $foo may contain 'abc' after running this example, even if the match wasn't successful? -- Brent Dax Royal-Gordon [EMAIL PROTECTED] Perl and Parrot hacker Oceania has always been at war with Eastasia.
Re: Mutating methods
Brent Dax Royal-Gordon wrote: / $foo:=(abc) $bar:=(def) / Am I misreading, or are you suggesting that $foo may contain 'abc' after running this example, even if the match wasn't successful? No. I re-checked with Larry this morning and he confirmed that all bindings in rules only stick if the rule as a whole succeeds. What I was trying (obviously rather ineptly ;-) to point out is that we have to be able to differentiate between the the match object's own internal hypothetical variables ($?foo, $?bar, @?baz) and any external-but-temporarily-hypothesized variables ($foo, $bar, @baz). The syntax we've chosen to do that requires the use of ? as a secondary sigil on internal variables. So, since named subrules that capture always capture to internal variables, it's natural and consistent to use ? to indicate capturing subrules as well. Damian
RE: Mutating methods
I was thinking along the lines of... String $foo = hello; $foo.scramble! print $foo\n; $foo = hello print $foo.scramble ~ \n; print $foo; OUTPUT (or close): elhlo hloel hello Also, along these same things.. is there a way to apply a method to all variables/objects of a certain type (e.g. String, Num, etc)? Taking the above example.. being able to write a method called Scramble that can be called as a method from any String type.
Re: Mutating methods
On Wed, Mar 10, 2004 at 10:46:05PM -0500, matt wrote: : I was thinking along the lines of... : : String $foo = hello; : $foo.scramble! That would be $foo.=scramble in the current scheme of things. : print $foo\n; : $foo = hello : print $foo.scramble ~ \n; : print $foo; : : OUTPUT (or close): : elhlo : hloel : hello : : Also, along these same things.. is there a way to apply a method to all : variables/objects of a certain type (e.g. String, Num, etc)? Taking the : above example.. being able to write a method called Scramble that can be : called as a method from any String type. Two ways, actually. You can 'reopen the String class and add the method: class String is extended { method scramble () returns String {...} } or if you consider that underhanded, you can define a multi-sub: multi sub *scramble (String $s) returns String {...} If you call that as a method, and there is no ordinary scramble method, it will fail soft to looking for a scramble multimethod, and end up calling your definition. Or you can just call it directly as a function: scramble(hello) Larry
RE: Mutating methods
-Original Message- From: Damian Conway [mailto:[EMAIL PROTECTED] Sent: Wednesday, 10 March, 2004 09:48 PM To: [EMAIL PROTECTED] Subject: Re: Mutating methods Brent Dax Royal-Gordon wrote: / $foo:=(abc) $bar:=(def) / Am I misreading, or are you suggesting that $foo may contain 'abc' after running this example, even if the match wasn't successful? No. I re-checked with Larry this morning and he confirmed that all bindings in rules only stick if the rule as a whole succeeds. What I was trying (obviously rather ineptly ;-) to point out is that we have to be able to differentiate between the the match object's own internal hypothetical variables ($?foo, $?bar, @?baz) and any external-but-temporarily-hypothesized variables ($foo, $bar, @baz). The syntax we've chosen to do that requires the use of ? as a secondary sigil on internal variables. So, since named subrules that capture always capture to internal variables, it's natural and consistent to use ? to indicate capturing subrules as well. Isn't this backwards? That is, from the above I get the impression that $?foo is TRANSIENT, while capturing to $foo will (eventually) be PERMANENT. So ?foo is just a shorthand way of saying $?foo := foo right? Is hypo-space a flat entity, or do hypothetical scopes nest? If so, do we have to use repeated ?'s, or will just one suffice? That is: rule bar {...} rule baz {...} rule foo {...bar...baz...} if / ?foo ... ?baz ... { $?foo.?baz ... $?baz } .../ OR if / ?foo ... ?baz ... { $?foo.baz ... $?baz } .../ OR if / ?foo ... ?baz ... { $?baz ... $?otherbaz } .../ =Austin
Re: Mutating methods
On Thu, Mar 11, 2004 at 01:09:59AM -0500, Austin Hastings wrote: : : : -Original Message- : From: Damian Conway [mailto:[EMAIL PROTECTED] : Sent: Wednesday, 10 March, 2004 09:48 PM : To: [EMAIL PROTECTED] : Subject: Re: Mutating methods : : : Brent Dax Royal-Gordon wrote: : : / $foo:=(abc) $bar:=(def) / : : Am I misreading, or are you suggesting that $foo may contain : 'abc' after : running this example, even if the match wasn't successful? : : No. I re-checked with Larry this morning and he confirmed that : all bindings in : rules only stick if the rule as a whole succeeds. : : What I was trying (obviously rather ineptly ;-) to point out is : that we have : to be able to differentiate between the the match object's own internal : hypothetical variables ($?foo, $?bar, @?baz) and any : external-but-temporarily-hypothesized variables ($foo, $bar, @baz). : : The syntax we've chosen to do that requires the use of ? as a secondary : sigil on internal variables. So, since named subrules that capture always : capture to internal variables, it's natural and consistent to use ? to : indicate capturing subrules as well. : : Isn't this backwards? : : That is, from the above I get the impression that $?foo is TRANSIENT, while : capturing to $foo will (eventually) be PERMANENT. $?foo is exactly as transient as the $0 in which it resides. So it really depends on how long $0 lives outside the regex. In the case of a returned parse tree it could live a very long time. : So ?foo is just a shorthand way of saying : :$?foo := foo : : right? Yes. The ? is actually serving as a scope marker telling Perl not to scan outside of the current regex for a variable of that name. If you consider each rule to be its own package, it's kind of an our declaration within the rule. : Is hypo-space a flat entity, or do hypothetical scopes nest? Um, the namespace inside a particular rule is flat, just as the namespace inside a package is flat. That doesn't mean that your code won't visit those variables in whatever order it jolly well pleases. Dynamically speaking, every assertion in a regex is recursively matched inside the results of previous successful assertions, regardless of the lexical structure of the rule. You're often in situations where dynamically you're going down recursively, while in terms of where you are in the match, you're going out of brackets or parens. It has to be that way, or you could never backtrack into a set of brackets or parents. But once a subrule is matched, all its ? names are bundled up into a hash in the single $0-ish object that becomes aliased (at least temporarily) to the $?foo in the outer rule. The keys of that hash are flat for all the names in the particular rule, though of course some of the values may be nested $0 results from subrules. So effectively you end up with a hash of hash of hash of hash representing the entire syntax tree. But any given rule can't produce more than one level of hash (without doing something freaky like rewriting your hash entries inside a closure). : If so, do we : have to use repeated ?'s, or will just one suffice? : : That is: : :rule bar {...} :rule baz {...} :rule foo {...bar...baz...} : :if / ?foo ... ?baz ... { $?foo.?baz ... $?baz } .../ : OR :if / ?foo ... ?baz ... { $?foo.baz ... $?baz } .../ : OR :if / ?foo ... ?baz ... { $?baz ... $?otherbaz } .../ Well, you don't need ? to go down the syntax tree, since each $0 can behave as a hash. You don't subscript hashes using . either. You subscript hashes with {...} historically, or these days, «...», when you want constant subscripts. So what you're looking for is something like: if / ?foo ... ?baz ... { $?foo{'baz'} ... $?baz } .../ or if / ?foo ... ?baz ... { $?foo«baz» ... $?baz } .../ or even: if / ?foo ... ?baz ... { $0«foo»«baz» ... $0«baz» } .../ Oh, and since the current $0 is actually the topic of any closure, you can also probably say if / ?foo ... ?baz ... { .«foo»«baz» ... .«baz» } .../ as an analog to if / ?foo ... ?baz ... { .{'foo'}{'baz'} ... .{'baz'} } .../ That's presuming we keep the rule that scalars don't have to include the sigils. For an array you'd still have to say: if / @?things:=[ (ident) ,? ]+ { ... [EMAIL PROTECTED] ... } / or if / @?things:=[ (ident) ,? ]+ { ... [EMAIL PROTECTED] ... } / But then it's usually easier just to say if / @?things:=[ (ident) ,? ]+ { ... @?things ... } / which means exactly the same thing. Larry