Re: Musings on operator overloading
Thom Boyer wrote: Now, I think that $x.foo is a method call, even if there's a postfix: declaration in scope. And that's a problem, because, no matter what precedence postfix: was given, 1,2,3.foo is still going to mean 1, 2, (3.foo) instead of the desired postfix:(1,2,3) The way I wrote that, it sounds like I think postfix: isn't a method call, but of course it is. What I really meant to say is that, in 1,2,3.foo the precedence of foo gets changed to the precedence of dot. I don't actually know that that is true. Is it? And does dot always do that? If it does, then something odd happens. Consider infix:<*> and postfix:, where infix:<*> binds tighter than postfix:<+>, and both bind more loosely than dot. Then 1 * 2! # means (1 * 2)! 1 * 2.! # means 1 * (2!) Methinks one or more of my assumptions is erroneous, 'cuz that's just too ugly to live. =thom
Re: Musings on operator overloading
Thom Boyer wrote: And does dot always do that? If it does, then something odd happens. Consider infix:<*> and postfix:, where infix:<*> binds tighter than postfix:<+>, and both bind more loosely than dot. Then I meant "... tighter than postfix:, ..." 1 * 2! # means (1 * 2)! 1 * 2.! # means 1 * (2!) Methinks one or more of my assumptions is erroneous, 'cuz that's just too ugly to live. =thom
Re: Musings on operator overloading
HaloO, Larry Wall wrote: I deem that to be an unlikely failure mode, however. So maybe .++ is just gone now, and you have to write \++ instead. Any objections? Please keep .++ as outlined below. Does the degenerate unspace not collide with &prefix:<\>? That is does foo\bar() not mean to capture the result from bar() and call foo with it unflattened? I'm not sure that's a great loss. It does suggest an alternate approach, though, which is to keep the .() forms with forced method precedence, and only require \x form for alpha postfixes that want to keep their own precedence. Not sure if I like that entirely, but it could fall out naturally from the definition of unspace in the current scheme of things, so maybe it's a non-issue. As it stands the .() forms are a great way to stack ops after a term. Together with knowing about the ops on the symbolic unary level you can easily read expressions from the terms outwards. Good practice would then be to join these extended terms by an obvious set of infix ops---usually one. The only twists to learn in this scheme would be ++, -- and **. Another good use of the dot forms is to get a single character form to tighten precedence: $x**3! != $x**3.! == $x**(3!). This is kind of reverse visually, though. So one might be tempted to make ! tighter than ** and get the looser meaning with $x**2\! which wouldn't be a degenerate unspace but a special form to unbind a tight op as in $x**$y\++ == ($x**$y)++ disregarding the fact that $x**$y is no lvalue. BTW, are there still the * and ** prefix ops for list flattening? Or are these superseded by prefix |? and maybe even &circumfix:<| |> ::= &prefix:; |$x| except for the fact that that would collide with prefix:<|>... So no whitespace dwimmery here? I.e. one would need |$x | to force the second | into infix? But eventually the parser has to give up when the same symbol is overloaded as prefix, postfix, infix and symmetric circumfix anyway. Regards, TSa. -- The Angel of Geometry and the Devil of Algebra fight for the soul of any mathematical being. -- Attributed to Hermann Weyl
Re: Musings on operator overloading
HaloO, TSa wrote: Another good use of the dot forms is to get a single character form to tighten precedence: $x**3! != $x**3.! == $x**(3!). BTW, is the dot form only available for postfix or for infix as well? I.e. 3 * 2 == 3.*(2)? Regards, TSa. -- The Angel of Geometry and the Devil of Algebra fight for the soul of any mathematical being. -- Attributed to Hermann Weyl
Re: Musings on operator overloading
HaloO, Jon Lang wrote: TSa wrote: Note that I see ** more as a parametric postscript then a real binary. That is $x**$y sort of means $x(**$y). That's where we differ, then. I'm having trouble seeing the benefit of that perspective, and I can clearly see a drawback to it - namely, you have to think of infix:<**> as being a different kind of thing than infix:.«<+ - * />, despite having equivalent forms. I see no drawback but a necessity because of the following asymmetry: 3 * 2 == 3 + 3 == 2 + 2 + 2; 3 **2 == 3 * 3 != 2 * 2 * 2; So ** more behaves like 3.pow(2) and overloading ** with non-numeric types on the right is questionable. Certain overloads of the left side might even require the right side to be (unsigned) integer. And of course $any ** $int === [*]($any xx $int) should hold. Regards, TSa. -- The Angel of Geometry and the Devil of Algebra fight for the soul of any mathematical being. -- Attributed to Hermann Weyl
Re: Musings on operator overloading
Jon Lang wrote: Thom Boyer wrote: That seems better to me than saying that there's no tab character in say "blah $x\t blah" Whoever said that? Oops. I thought Larry did. But he didn't; I misread it. Whew. Somehow I managed to read Larry's words and get exactly the *opposite* meaning from what he actually wrote: Larry Wall wrote: > This may also simplify the parsing rules inside double quoted > strings if we don't have to figure out whether to include postfix > operators like .++ in the interpolation. It does risk a visual > clash if someone defines postfix:: > > $x\t # means ($x)t > "$x\t" # means $x ~ "\t" How embarrassing. Thanks for asking "Whoever said that?", because it forced me to go reread it. I think I'd better go reread the whole thing. More carefully this time. > Thom Boyer wrote: >> when (if I understand correctly) you could write that as simply as >> >> 1,2,3 say > > Nope. This is the same situation as the aforementioned '++' example, > in that you'd get into trouble if anyone were to define an infix: > operator. OK. Let me see if I get this. First, let me state my understanding of the issue with ++ (where ++ is actually a stand-in for *any* operator that is both postfix and infix): $x++ # postfix operator, because there's no whitespace $x.++# postfix (the dot is optional) $x ++# infix operator, because there's whitespace $x\ ++ # postfix: space isn't allowed, but unspace is $x\ .++ # postfix (the dot is still optional) Question: given ($x)++ # no whitespace, so postfix? is ++ postfix, or infix? Now, I think that $x.foo is a method call, even if there's a postfix: declaration in scope. And that's a problem, because, no matter what precedence postfix: was given, 1,2,3.foo is still going to mean 1, 2, (3.foo) instead of the desired postfix:(1,2,3) so Larry has proposed 1,2,3\foo # means: postfix:(1, 2, 3) as a way to get the desired meaning without having to resort to parentheses. So the point is that a nospace unspace acts like dot, in that it turns the following operator into a postfix operator. But it doesn't have the undesired characteristic that it turns an intended postfix operator into a method dispatch. Have I got that right, or am I still wandering in a wilderness that is completely disconnected from Larry's proposal? Final question: I think these are all equivalent. Are they? 1,2,3\foo (1,2,3)foo (1,2,3).foo postfix:(1,2,3) =thom
Re: Musings on operator overloading
Is it just me, or is all this talk about precedence and functions vs operators vs methods creating a niggling sensation in anyone else's head? It feels like we're in the vicinity of another one of them Big Simplifying Idea things. Unfortunately, I don't have the actual Big Idea, so it could just be a false alarm. On the one hand, I'm worried that Perl6 is going to turn into the computer equivalent of Quenya, which was never completed because its creator couldn't stop tinkering. (No offense to Larry intended..) On the other, given how much design thought has gone into it thus far, much of it radical, it would be terrible to miss an opportunity to do something great in the rush to git 'er done.
Re: Musings on operator overloading
On Wed, Mar 26, 2008 at 07:32:23PM -0600, Thom Boyer wrote: > Question: given > > ($x)++ # no whitespace, so postfix? > > is ++ postfix, or infix? That is postfix. Any infix that could be confused with a postfix requires intervening whitespace. > Now, I think that > > $x.foo > > is a method call, even if there's a postfix: declaration in scope. And > that's a problem, because, no matter what precedence postfix: was > given, > > 1,2,3.foo > > is still going to mean > > 1, 2, (3.foo) > > instead of the desired > > postfix:(1,2,3) > > so Larry has proposed > > 1,2,3\foo # means: postfix:(1, 2, 3) > > as a way to get the desired meaning without having to resort to parentheses. > > So the point is that a nospace unspace acts like dot, in that it turns the > following operator into a postfix operator. But it doesn't have the > undesired characteristic that it turns an intended postfix operator into a > method dispatch. Have I got that right, or am I still wandering in a > wilderness that is completely disconnected from Larry's proposal? The .++ form is still not a method (single) dispatch, just an alternate form of the postfix, which is a multi dispatch. The basic problem is that .i is ambiguous, and by the current standard grammar is not resolved by LTM because it's a tie. We could maybe fix that by changing it so the "meth" part of .meth isn't counted as part of the same token, but right now it is. Or we could bias .meth forms toward single dispatch (which might work the same, depending on whether there's an equivalent method definition, which often there is, especially if the multi is defined as just an exported method). > Final question: I think these are all equivalent. Are they? > > 1,2,3\foo > (1,2,3)foo > (1,2,3).foo > postfix:(1,2,3) At the moment, the .foo form is officially ambiguous, so might end up going through single dispatch instead of multi dispatch. To the casual reader it looks like it should be single dispatch. That's what is bugging me. Well, one of the things... The current tie-breaker on longest token matching is to use rule ordering, but that's not terribly robust. Larry
Re: Musings on operator overloading
On Thu, Mar 27, 2008 at 01:01:27PM +0100, TSa wrote: > HaloO, > > Larry Wall wrote: >> I deem that to be an unlikely failure mode, however. So maybe .++ >> is just gone now, and you have to write \++ instead. Any objections? > > Please keep .++ as outlined below. Does the degenerate unspace not > collide with &prefix:<\>? That is does foo\bar() not mean to capture > the result from bar() and call foo with it unflattened? No, listops require a space after if there are any arguments. >> I'm not sure that's a great loss. It does suggest an alternate >> approach, though, which is to keep the .() forms with forced method >> precedence, and only require \x form for alpha postfixes that want >> to keep their own precedence. Not sure if I like that entirely, >> but it could fall out naturally from the definition of unspace in >> the current scheme of things, so maybe it's a non-issue. > > As it stands the .() forms are a great way to stack ops after > a term. Together with knowing about the ops on the symbolic unary > level you can easily read expressions from the terms outwards. > Good practice would then be to join these extended terms by an > obvious set of infix ops---usually one. The only twists to learn in > this scheme would be ++, -- and **. I don't follow that. Example? > Another good use of the dot forms is to get a single character > form to tighten precedence: $x**3! != $x**3.! == $x**(3!). This > is kind of reverse visually, though. Unless you count precedence forcing as "more work" in some sense. :) > So one might be tempted to > make ! tighter than ** and get the looser meaning with $x**2\! > which wouldn't be a degenerate unspace but a special form to > unbind a tight op as in $x**$y\++ == ($x**$y)++ disregarding the > fact that $x**$y is no lvalue. That seems unnecessarily convoluted for a rarely used item. > BTW, are there still the * and ** prefix ops for list flattening? > Or are these superseded by prefix |? The * and ** prefixes are gone. We have * and ** as bare terms now, which precludes their being used as a prefix. Lists may be dereferenced into capture context with |, or into list context with @ or @@. >> and maybe even >> >> &circumfix:<| |> ::= &prefix:; >> |$x| >> >> except for the fact that that would collide with prefix:<|>... > > So no whitespace dwimmery here? I.e. one would need |$x | to > force the second | into infix? But eventually the parser has > to give up when the same symbol is overloaded as prefix, postfix, > infix and symmetric circumfix anyway. We don't do that kind of lookahead, nor should we force the reader to do it. Circumfixes are recognized only by their initial token, and therefore live in the same slot as prefixes. The final token is used only to validate the termination of the inner expression. Any other approach is likely to confuse both the compiler and the user. Note that the human brain is not well wired to do lookahead in linguistic processing, since you'd have to know what was not yet uttered by the speaker. N-token lookahead schemes are good for academic papers but not so good for users. You can cheat a bit visually, but it's not terribly efficient to have to glance ahead in any case. Larry
Re: Musings on operator overloading
On Thu, Mar 27, 2008 at 01:08:43PM +0100, TSa wrote: > HaloO, > > TSa wrote: >> Another good use of the dot forms is to get a single character >> form to tighten precedence: $x**3! != $x**3.! == $x**(3!). > > BTW, is the dot form only available for postfix or for infix > as well? I.e. 3 * 2 == 3.*(2)? Only postfix. (And we already use .* for something else.) You can probably get away with 3.infix:<*>(2) though. However, note also that operators are intended to be dispatch using multiple dispatch, not single. Multiple dispatch allows the language to defined the operator without getting the object involved. Single dispatch has to rely on the semantics of the object itself to determine the meaning of a method. This becomes important when we have objects from outside of Perl. $a + $b is always addition under multiple dispatch, but $a.infix:<+>($b) might do concatenation if $a is a foreign object from a language that (mis)treats + that way. Larry
Re: Musings on operator overloading
On Thu, Mar 27, 2008 at 09:46:29AM -0400, Mark J. Reed wrote: : Is it just me, or is all this talk about precedence and functions vs : operators vs methods creating a niggling sensation in anyone else's : head? It feels like we're in the vicinity of another one of them Big : Simplifying Idea things. Unfortunately, I don't have the actual Big : Idea, so it could just be a false alarm. We're in the vicinity of a lot of big ideas here, but most of them are already thunk of and documented in one of the synopses. I think any additional Big Simplifying Ideas at this point would only simplify things for us, not for the user (which is the usual failure mode of Big Simplifying Ideas). : On the one hand, I'm worried that Perl6 is going to turn into the : computer equivalent of Quenya, which was never completed because its : creator couldn't stop tinkering. (No offense to Larry intended..) On : the other, given how much design thought has gone into it thus far, : much of it radical, it would be terrible to miss an opportunity to do : something great in the rush to git 'er done. Um, you're missing something basic here; most of the radical design we have so far is there *precisely* because it will allow us to publish snapshots of the language without ever finishing the language. :) If you can't fix it, feature it... Larry
Re: Musings on operator overloading
Larry Wall wrote: The .++ form is still not a method (single) dispatch, just an alternate form of the postfix, which is a multi dispatch. But the postfix is a unary operator, right? So that'd be multi dispatch on one argument. How does single dispatch differ from multi dispatch on a single argument? =thom
Re: Musings on operator overloading
On Thu, Mar 27, 2008 at 09:02:37AM -0600, Thom Boyer wrote: > Larry Wall wrote: >> The .++ form is still not a method (single) dispatch, just an alternate >> form of the postfix, which is a multi dispatch. > > But the postfix is a unary operator, right? So that'd be multi dispatch on > one argument. Correct. > How does single dispatch differ from multi dispatch on a single argument? The question is, who's to be master, that's all. :) Single dispatch asks the object's MOP (meta-object protocol) to dispatch through its .HOW interface, so it depends on which metaobject system the object was born under. Multiple dispatch, in contrast, pays attention only to the type information that comes from the .WHAT interface, and doesn't ask the MOP to do the dispatch. It is external to any MOP, except insofar as the MOP gets involved to help define how .WHAT returns type information. But types are considered largely declarative, not procedural. (This view of single dispatch is slightly oversimplified, insofar as the MOP typically sets up an efficient responder interface that handles the actual dispatch without having to redecide every time.) Practically speaking, the main difference is "foo $x" looks for a function with one argument, while $x.foo looks for a method with no arguments. multi sub foo ($x) { say "I am a function" } vs. method foo () { say "I am a method" } The candidate list for multis is constructed from all longnames visible in the current lexical scope, and there is no inheritance involved, only importation of function names (which, for so-called built-in functions, is done by the Prelude from the various modules those functions are defined in). The candidate list for methods is determined by the MOP, but generally follows class hierarchy for class-based OO. A routine can be visible via both routes, but only by some form of aliasing. The "close" method/function is defined something like: class IO; ... method close () is export {...} and when the Prelude does "use IO" it imports the close method not as method, but as a function, as if you'd said: multi close (IO $self) {...} or some such. And since mutlis are lexically scoped, and operators are just macros that translate to function calls, and longnames from different scopes are interleaved, it means we have lexically-scoped overloading if you want it. The other ramification is that we get to define our operators independently of what the object might think the operator means, even if it comes from another language. These may mean two entirely different things if $a comes from, say, Python or Java or Perl 5: $a + $b # always addition in Perl 6 $a.'+'($b) # depends on language of $a More subtly, the same distinction happens with unaries: +$a # always numification in Perl 6 $a.prefix<+># depends on language of $a Larry