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 C. 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 = 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:= gets remapped to self:. 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 C too, perhaps? Damian
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 C, 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 C 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
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
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 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, 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 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 = 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:= gets remapped to self:. 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 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 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 and an = 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 C 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 @array.self:sort.self:uni
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
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
> "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 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
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