Re: Overloading Roles
On 2009-Oct-5, at 3:41 pm, Jon Lang wrote: Concerning that last one: would it be reasonable to have a Discrete role that provides a .succ method, and then overload the Range role? I think a type needs to be Discrete and Ordered for successors to make sense (e.g. consider a discrete unordered type like Complex ints). I'm still thinking a Discrete type is the same as a Set; so perhaps Discrete Ordered means Positional? But that doesn't feel right -- although any ordered set can be represented as an array, that seems to confuse the idea of order that is intended. (And perhaps Discrete should be a different type from Set even if they do work out the same, simply to better document one's intent.) -David
Re: Overloading Roles
Jon Lang wrote: Concerning that last one: would it be reasonable to have a Discrete role that provides a .succ method, and then overload the Range role? E.g.: role Range[Ordered ::T] { ... } role Range[Ordered Discrete ::T] { ... method iterator ( - RangeIterator ) { ... } } If so, then this approach might also be used to handle the special behavior that comes with Numeric types: role Range[Ordered Numeric ::T] { ... } If the question is can you define multiple roles with the same name, but taking different signatures, then the answer is yes, and that it goes by the same rules as multiple dispatch (and it's even been implemented :-)). What you pasted won't quite work, however, as you can't write multiple types before a parameter (at least in 6.0.0). So you'd want something more like: role Range[::T where Ordered Numeric] { ... } Hope this helps, Jonathan
Overloading Roles
Consider a Range role that is parameterized (i.e., Range of T is a perfectly valid thing to do). According to the spec, the definition of Range depends on the nature of T: * If the lower bound is Numeric, certain coercion rules are attempted on the upper bound; otherwise, the two boundaries must have the same type. ** Speculation: if the lower bound is a Whatever, the boundary type should be determined by the upper bound; if both are Whatever, treat it as Numeric? * if the boundary type has a .succ method, then the Range can provide a RangeIterator; otherwise, it can't. Concerning that last one: would it be reasonable to have a Discrete role that provides a .succ method, and then overload the Range role? E.g.: role Range[Ordered ::T] { ... } role Range[Ordered Discrete ::T] { ... method iterator ( - RangeIterator ) { ... } } If so, then this approach might also be used to handle the special behavior that comes with Numeric types: role Range[Ordered Numeric ::T] { ... } -- Jonathan Dataweaver Lang
Re: Musings on operator overloading
HaloO, Larry Wall wrote: 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. I'm not actually parsing expressions. Or as you point out below with respect to look-ahead I'm bad at it as a human. But as a human I've got a 2D vision and mathematical expressions are inherently 2D on paper. So they are more like a drawing than a writing. The poor equivalent in a programming language is whitespace markup. Consider the triangle inequality: |$x+$y| = |$x| + |$y| This nicely breaks apart into five clusters of characters. I recognize the two infix ops = and + and bring my precedence knowledge to bear or look it up. After that I analyze the remaining three clusters. I see all of them having | as first and last character. So I know that three absolute values are linked by two operators. And only then do I start to analyze the things inside the | |s which gives me the sum of $x and $y and the same values separately. The version with more spaces is different |$x + $y| = |$x| + |$y| because now I tend to perceive the two +s on equal footing and converge visually on |$x using prefix | and $y| postfix. To avoid that an ASCII equivalent of a typesetting system gives | $x + $y | = | $x | + | $y | to guide my visual distance parsing or however that might be called. 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? The twist of ++, -- and ** is that they lay between method and symbolic unary precedence and that ** is the only binary operator with tighter precedence then the symbolic unarys. By operator stacking I mean something like !+-~?|+^~^$x.a.b.c + [EMAIL PROTECTED] which splits into two blobs left and right of + each of which has a sigiled term as nucleus. From there I would work outwards in operator precedence. In other words, writing the former example as $x ** $y! visually attaches ! to $y and deters from the precedence issue. So it should be something like $x**$y\ ! to highlight it. But parens aren't that bad here either ($x ** $y)! But the tight precedence of infix ** should be made obvious by not surrounding it with whitespace. Which gives ($x**$y)! as the best option. I would make more infix ops list like. We already have , associative, non-commutative | ^ associative, commutative and could add ~ into the first group and *, +, +, +|, ~, ~, +^ and ~^ into the second one. The code generator and the optimizer would use these features and give erroneous results when overloads don't respect them. 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
At 09:46 -0400 3/27/08, 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. At 16:24 +0100 3/26/08, TSa wrote: I agree. But let me explain how I arrive at that. To me there is no binary minus! -f(x) - g(x) = -f(x) + -g(x) = -g(x) + -f(x). I.e. plus is commutative. In other words overloading unary minus gives you the binary version for free. Or even better is to deeply overload unary plus to do the Ring role. Additionally implementing unary / or 1/ or so would yield the Field role. At 17:06 +0100 3/20/08, TSa wrote: BTW, do we have a unary multiplikative inversion operator? That is 1/ as prefix or **-1 as postfix? Perhaps .inv as method? Do we have .neg for additive inversion? This is becoming a night time habit. I really need to spend a whole lot of time learning the new operator syntax and Perl 6 Essentials 1st edition isn't going to cut it. Following Mark's line of thought, that bothers me. Thomas' idea that there is no such thing as a binary minus operator and his question about inversion operators intrigue me. Perhaps there is a way to a breakthrough that would be acceptable to long-time users of the chalkboard and still be mathematically pure and and easily parsed. A while back there was a flurry of new math being taught in US elementary schools. The idea was to introduce set theory early and avoid the re-learning necessary when groups and fields are introduced later. It was a failure mostly because the teachers couldn't understand it. A group is a set with a single binary operator defined, the result of that operator is a member of the group, there is a null member of the group that returns the value of the other operand, and every member of the group has an inverse for which the operation returns the null. Note that those axioms say nothing about an inversion operator. For numbers the operator is either addition, +, or multiplication, *. Subtraction and division are notably missing. A field is a set which looks like two kinds of group with two operators. One operator has higher precedence than the other and the existence of the inverse for one operator requires some modification for the null of the other operator. Matrices and vectors are reasonably comfortable in fields. Note that commutativity is not a group requirement. The vector cross product is a bit strange but some folks claim that a cross product is really an antisymmetric tensor that isn't really a vector because it doesn't transform, under reflection, as the coordinate differentials. That kind of thinking would fit right in and might be beneficial. Overloading code would be required for * and + only but inversions would replace that bit of simplification. Note that the term class acquires a close relationship with the term field. I think it is possible to insist that users of perl 6 for math think in terms of fields while writing expressions. Just remove the / and - operators from the language. They're not present in the field axioms so why have them? Just announce that perl 6 will be different. The rest of the world now listens when we say a perl regular expression. Why not the same for perl math expression ?. NIST now likes people to avoid the term per when writing about dimensions of physical quantities. A watt is a kg*m**2*s**-2 when translated to perl 5 but it looks a lot better in print with superscripts and no explicit * operator. Calling it a kilogram meter squared per second per second has been deprecated for years. Engineers and physicists known to me have no problem with it. There was once a mnemonic, PEMDAS, that was taught in algebra classes. Parentheses, exponentiation, multiplication, division, addition, subtraction was the order to use when working with algebraic expressions. Restricting that to fields would change it to PFMA by which I mean parentheses, functions, multiplication, addition. Functions would include exponentiation along with other things like inversion and more complicated library functions.. Users would have to learn that division and subtraction would be called out by an inversion followed by a multiply or add operation. Terms on the right side of the replacement operator would be separated by + signs only. Needed would be a really simple syntax for the two types of inversion. Something like a distinct sigl would be nice from a user's point of view. $xxx[$n] is closely associated with @xxx and it seems possible to come up with something like Nxxx for the additive inversion of $xxx and Dxxx for its multiplicative equivalent. Variables starting with I through N was not a bad way to indicate an integer. I haven't any idea how one would request that a function
Re: Musings on operator overloading
Thom Boyer wrote: Now, I think that $x.foo is a method call, even if there's a postfix:foo declaration in scope. And that's a problem, because, no matter what precedence postfix:foo was given, 1,2,3.foo is still going to mean 1, 2, (3.foo) instead of the desired postfix:foo(1,2,3) The way I wrote that, it sounds like I think postfix:foo 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:abs; |$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:t: $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:say 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:foo declaration in scope. And that's a problem, because, no matter what precedence postfix:foo was given, 1,2,3.foo is still going to mean 1, 2, (3.foo) instead of the desired postfix:foo(1,2,3) so Larry has proposed 1,2,3\foo # means: postfix:foo(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:foo(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:foo declaration in scope. And that's a problem, because, no matter what precedence postfix:foo was given, 1,2,3.foo is still going to mean 1, 2, (3.foo) instead of the desired postfix:foo(1,2,3) so Larry has proposed 1,2,3\foo # means: postfix:foo(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:foo(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:abs; |$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
Re: Musings on operator overloading
At 21:40 +0100 3/25/08, TSa wrote: Doug McNutt wrote: Don't allow it ( = - f($x); )to become = f(-$x); ## wrong! Unless of course f does Linear, then you can factor out or in the multiplication with -1 at will. So linearity of operators and functions is a very interesting property for optimizers. Well. . . I was going to let it pass but I had trouble sleeping this morning because of it. f($x) = constant + $x would certainly be considered a linear function with constant derivative but for that definition -f($x) is not the same as f(-$x). I think the appropriate term is antisymmetric to indicate -f(x) = f(-x). Examples would be sin(x), pow(x,3), 1/x, x**3. What worried me in the night is a comment in the Camel book that says the ** operator has a higher precedence than the unary minus with the clear implication, unfortunately true, that other languages declare the opposite. If that structure will persist into perl 6 there is a real danger that new postfix operators that are being talked about, multiplicative or additive inversion for example, may well need to be declared either symmetric or antisymmetric to keep an ambitious parser or optimizer under control. What is really needed is a more careful detection of the unary minus. In chalkboard algebra there is no such thing as a unary minus in an equation. A leading minus, one that follows an = sign or a left parenthesis, is interpreted as an implied subtraction from zero or perhaps an implied multiplication by negative unity. The unary minus only shows up in things like a list of numbers, the components of a vector (-1,2,-3) or numeric values arriving over a teletype link.. I think, but can't prove, that the discrepancy began with compiler compilers - yacc - where GUI programmers - Excel - saw an easy way to put formulas on a video tube. All they had to do was provide operator definitions and precedence rules. One possibility is to decide that unary minus does not exist in a replacement expression. Perform a clear and subtract assembly instruction. That would not matter for a common programming technique that defines a constant $negpi = -3.1416; instead of a real unary minus using *NEGPI = \-3.1416; or use constant NEGPI = -3.1416;. It's needs some updating but http://macnauchtan.com/pub/precedence.html is still on the net. The statements: = - f($x) - g($x); = - g($x) - f($x); should always return the same result regardless of whether f or g is implemented as a function, a method, or a postfix operator; and that should be true even if the - operator is overloaded. -- -- If you are presented a number as a percentage, and you do not clearly understand the numerator and the denominator involved, you are surely being lied to. --
Re: Musings on operator overloading
HaloO, Doug McNutt wrote: Well. . . I was going to let it pass but I had trouble sleeping this morning because of it. Sorry. f($x) = constant + $x would certainly be considered a linear function No, I was talking about the other linear ;) with constant derivative but for that definition -f($x) is not the same as f(-$x). I think the appropriate term is antisymmetric to indicate -f(x) = f(-x). Examples would be sin(x), pow(x,3), 1/x, x**3. That's a weaker property known also as even and odd functions because their power series contain only even or odd powers. Linearity means $a*f($x) == f($a*$x) f($x+$y) == f($x)+f($y). The statements: = - f($x) - g($x); = - g($x) - f($x); should always return the same result regardless of whether f or g is implemented as a function, a method, or a postfix operator; and that should be true even if the - operator is overloaded. I agree. But let me explain how I arrive at that. To me there is no binary minus! -f(x) - g(x) = -f(x) + -g(x) = -g(x) + -f(x). I.e. plus is commutative. In other words overloading unary minus gives you the binary version for free. Or even better is to deeply overload unary plus to do the Ring role. Additionally implementing unary / or 1/ or so would yield the Field role. 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
On Wed, Mar 26, 2008 at 11:24 AM, TSa [EMAIL PROTECTED] wrote: I agree. But let me explain how I arrive at that. To me there is no binary minus! I must agree with that one. In chalkboard mathematics, - is a unary negation operator, and its use as a binary op in x - y is just shorthand for x + -y. -- Mark J. Reed [EMAIL PROTECTED]
Re: Musings on operator overloading
On Wed, Mar 26, 2008 at 12:04:43PM -0400, Mark J. Reed wrote: : On Wed, Mar 26, 2008 at 11:24 AM, TSa [EMAIL PROTECTED] wrote: : I agree. But let me explain how I arrive at that. To me there is no : binary minus! : : I must agree with that one. In chalkboard mathematics, - is a unary : negation operator, and its use as a binary op in x - y is just : shorthand for x + -y. That interpretation doesn't help me solve my generic parsing problems, which is about the relationship of op1 to op2 and op3 in op1 a() op2 b() op3 c() and presumably the same thing for postfixes in the other order. So here's another question in the same vein. How would mathematicians read these (assuming Perl has a factorial postfix operator): 1 + a(x)**2! 1 + a(x)²! Larry
Re: Musings on operator overloading
HaloO, Larry Wall wrote: That interpretation doesn't help me solve my generic parsing problems, which is about the relationship of op1 to op2 and op3 in op1 a() op2 b() op3 c() and presumably the same thing for postfixes in the other order. My idea is to have a term re-writing stage before the precedence parser does its job. I assume that chalkboard mathematics means term re-writing. Which sort of means that infix:-($x,$y) is a macro that expands to infix:+($x,prefix:-($y)). So here's another question in the same vein. How would mathematicians read these (assuming Perl has a factorial postfix operator): Without implying to actually being a mathematician I'll give my thoughts on the subject. 1 + a(x)**2! That is a poor version the the version below and obviously depends on the precedence that ! has relative to **. 1 + a(x)²! This means to me to square the return value of a(x), then take the factorial and then add 1. Getting a(x) raised to 2! would require the ! to be superscripted as well. Its ASCII version would explicitly require a(x)**(2!). So a(x)**2! is either ambiguous or requires lower precedence for !. My actual reading of the ASCII version picks a(x) as the operation with highest precedence and going from there outwards encountering + to the left and ** to the right with ** being of higher precedence. Then I'm left with + to the left and ! to the right with precedence of ! higher than +. I hope that helps, 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
On Wed, Mar 26, 2008 at 1:06 PM, TSa [EMAIL PROTECTED] wrote: 1 + a(x)²! Seems like a mathematician would be inclined to write that one as this instead: 1 + a²(x)! But I'm not suggesting that you try to make (a**2)(x) work for (a(x))**2 in Perl. :) -- Mark J. Reed [EMAIL PROTECTED]
Re: Musings on operator overloading
On Wed, Mar 26, 2008 at 06:06:29PM +0100, TSa wrote: HaloO, Larry Wall wrote: That interpretation doesn't help me solve my generic parsing problems, which is about the relationship of op1 to op2 and op3 in op1 a() op2 b() op3 c() and presumably the same thing for postfixes in the other order. My idea is to have a term re-writing stage before the precedence parser does its job. I assume that chalkboard mathematics means term re-writing. Which sort of means that infix:-($x,$y) is a macro that expands to infix:+($x,prefix:-($y)). Alas, you can't figure out which terms to rewrite until you've parsed them. So here's another question in the same vein. How would mathematicians read these (assuming Perl has a factorial postfix operator): Without implying to actually being a mathematician I'll give my thoughts on the subject. 1 + a(x)**2! That is a poor version the the version below and obviously depends on the precedence that ! has relative to **. 1 + a(x)²! This means to me to square the return value of a(x), then take the factorial and then add 1. Getting a(x) raised to 2! would require the ! to be superscripted as well. Its ASCII version would explicitly require a(x)**(2!). So a(x)**2! is either ambiguous or requires lower precedence for !. My actual reading of the ASCII version picks a(x) as the operation with highest precedence and going from there outwards encountering + to the left and ** to the right with ** being of higher precedence. Then I'm left with + to the left and ! to the right with precedence of ! higher than +. That's what I thought. Now note that ! can't easily be rewritten as a simple binary operator (unless you do something recursive, and then it's not simple). Now, I think I know how to make the parser use precedence on either a prefix or a postfix to get the desired effect (but perhaps not going both directions simulatenously). But that leads me to a slightly different parsing question, which comes from the asymmetry of postfix operators. If we make postfix:! do the precedence trick above with respect to infix:** in order to emulate the superscript notation, then the next question is, are these equivalent: 1 + a(x)**2! 1 + a(x)**2.! likewise, should these be parsed the same? $a**2i $a**2.i and if so, how to we rationalize a class of postfix operators that *look* like ordinary method calls but don't parse the same. In the limit, suppose some defines a postfix say looser than comma: (1,2,3)say 1,2,3say 1,2,3.say Would those all do the same thing? Or should we maybe split postfix dot notation into two different characters depending on whether we mean normal method call or a postfix operator that needs to be syntactically distinguished because we can't write $a.i as $ai? I suppose, if we allow an unspace without any space as a degenerate case, we could write $a\i instead, and it would be equivalent to ($a)i. And it resolves the hypothetical postfix:say above: 1,2,3.say # always a method, means 1, 2, (3.say) 1,2,3\ say # the normal unspace, means (1, 2, 3)say 1,2,3\say # degenerate unspace, means (1, 2, 3)say 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:t: $x\t# means ($x)t $x\t # means $x ~ \t I deem that to be an unlikely failure mode, however. So maybe .++ is just gone now, and you have to write \++ instead. Any objections? I suppose that means that .(), .[], and .{} would also be gone, in favor of \(), \[], and \{}. We'd given a different meaning to foo\() at one point, but I think that went away. And since these postfixes aren't alphanumeric, you don't need the degenerate unspace to separate them from a variable name. So you generally wouldn't see them unless you wanted $a\ () with extra whitespace. Another possible downside: getting rid of the .postop form also has the side effect of getting rid of these bare forms .++ # meaning ($_)++ .() # meaning ($_)() .[] # meaning ($_)[] .{} # meaning ($_.{} . # meaning ($_) .i # meaning ($_)i :) 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. And it makes it really easy to define postfixes equivalent to prefixes: postfix:- ::= prefix:-; $x\- postfix:abs ::= prefix:abs; $x\abs and maybe even circumfix:| | ::= prefix:abs; |$x| except for the fact that that
Re: Musings on operator overloading
Larry Wall wrote: So here's another question in the same vein. How would mathematicians read these (assuming Perl has a factorial postfix operator): 1 + a(x)**2! 1 + a(x)²! The 1 + ... portion is not in dispute: in both cases, everything to the right of the addition sign gets evaluated before the addition does. As such, I'll now concentrate on the right term. As TsA pointed out, mathematicians wouldn't write the former case at all; they'd use a superscript, and you'd be able to distinguish between a(x) to the two-factorial power and (a(x) squared) factorial based on whether or not the factorial is superscripted. So the latter would be (a(x) squared) factorial. OTOH, you didn't ask how mathematicians would write this; you asked how they'd read it. As an amateur mathematician (my formal education includes linear algebra and basic differential equations), I read the former as a(x) to the two-factorial power: all unary operators, be they prefix or postfix, should be evaluated before any binary operator is. -- Jonathan Dataweaver Lang
Re: Musings on operator overloading
On Wed, Mar 26, 2008 at 11:00:09AM -0700, Jon Lang wrote: : OTOH, you didn't ask how mathematicians would write this; you asked : how they'd read it. As an amateur mathematician (my formal education : includes linear algebra and basic differential equations), I read the : former as a(x) to the two-factorial power: all unary operators, be : they prefix or postfix, should be evaluated before any binary operator : is. Could we please get all the mathematicians in the world together to vote on this? :) I also wouldn't mind a straw vote from all the future mathematicians... Larry
Re: Musings on operator overloading
Larry Wall wrote: Now, I think I know how to make the parser use precedence on either a prefix or a postfix to get the desired effect (but perhaps not going both directions simulatenously). But that leads me to a slightly different parsing question, which comes from the asymmetry of postfix operators. If we make postfix:! do the precedence trick above with respect to infix:** in order to emulate the superscript notation, then the next question is, are these equivalent: 1 + a(x)**2! 1 + a(x)**2.! To me, both of these should raise a(x) to the 2-factorial power; so yes, they should be equivalent. likewise, should these be parsed the same? $a**2i $a**2.i In terms of form, or function? Aesthetically, my gut reaction is to see these parse the same way, as raise $a to the power of 2i; in practice, though, 2i on a chalkboard means 2 times i, where i is unitary. Hmm... Again, though, this isn't a particularly fair example, as mathematical notation generally uses superscripting rather than ** to denote exponents, allowing the presence or absence of superscripting on the i to determine when it gets evaluated. That is, the mathematical notation for exponents includes an implicit grouping mechanism. and if so, how to we rationalize a class of postfix operators that *look* like ordinary method calls but don't parse the same. In the limit, suppose some defines a postfix say looser than comma: (1,2,3)say 1,2,3say 1,2,3.say Would those all do the same thing? Gut reaction: the first applies say to the list 1, 2, 3; the second and third apply say to 3. Or should we maybe split postfix dot notation into two different characters depending on whether we mean normal method call or a postfix operator that needs to be syntactically distinguished because we can't write $a.i as $ai? I suppose, if we allow an unspace without any space as a degenerate case, we could write $a\i instead, and it would be equivalent to ($a)i. And it resolves the hypothetical postfix:say above: 1,2,3.say # always a method, means 1, 2, (3.say) 1,2,3\ say # the normal unspace, means (1, 2, 3)say 1,2,3\say # degenerate unspace, means (1, 2, 3)say 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. I'm in favor of the minimalist unspace concept, independent of the current concerns. In effect, it lets you insert the equivalent of whitespace anywhere you want (except in the middle of tokens), even if whitespace would normally be forbidden; and it does so in a way that takes up as little space as possible. It does risk a visual clash if someone defines postfix:t: $x\t# means ($x)t $x\t # means $x ~ \t I deem that to be an unlikely failure mode, however. :nod: Alphanumeric postfixes ought to be rare compared to symbolic postfixes. -- Jonathan Dataweaver Lang
Re: Musings on operator overloading
HaloO, Mark J. Reed wrote: On Wed, Mar 26, 2008 at 1:06 PM, TSa [EMAIL PROTECTED] wrote: 1 + a(x)²! Seems like a mathematician would be inclined to write that one as this instead: 1 + a²(x)! That one is ambiguous because it could mean a(a(x)) or a(x)*a(x) with the latter case being used for the trigonometric functions as exceptions to the former rule. But I'm not suggesting that you try to make (a**2)(x) work for (a(x))**2 in Perl. :) That might actually be written a**2($x) which is visually unpleasing because ** separates a and 2 while 2 and ($x) don't even have something in between. I'm tempted for quite a while now to start a thread called operator arithmetic discussing first class code value arithmetic. But I don't know if that is too far off this list. 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, Larry Wall wrote: That's what I thought. Now note that ! can't easily be rewritten as a simple binary operator (unless you do something recursive, and then it's not simple). Would $x! == [*]1..$x constitute simple parserwise? Admittedly it's not a single but two ops and one of them a meta. Now, I think I know how to make the parser use precedence on either a prefix or a postfix to get the desired effect (but perhaps not going both directions simulatenously). But that leads me to a slightly different parsing question, which comes from the asymmetry of postfix operators. How are postfix operators asymmetric? 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
On Wed, Mar 26, 2008 at 11:00:09AM -0700, Jon Lang wrote: : all unary operators, be they prefix or postfix, should be evaluated : before any binary operator is. And leaving the pool of voting mathematicians out of it for the moment, how would you parse these: sleep $then - $now not $a eq $b say $a ~ $b abs $x**3 These all work only because unaries can be looser than binaries. And Perl 5 programmers will all expect them to work, in addition to -$a**2 returning a negative value. And we have to deal with unary precedence anyway, or !%seen{$key}++ doesn't work right... Larry
Re: Musings on operator overloading
TSa wrote: Jon Lang wrote: all unary operators, be they prefix or postfix, should be evaluated before any binary operator is. 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. Note also that for certain operations only integer values for $y make sense. E.g. there's no square root of a function. ...as opposed to a square root of a function's range value. That is, you're talking in terms of linear algebra here, where D²(x) means D(D(x)), as opposed to basic algebra, where f²(x) means (f(x))². This is similar to your earlier the other Linear comment. This is a case where the meaning of an operator will depend on the system that you're dealing with. Math is full of these, especially when it comes to superscripts and subscripts. I'd recommend sticking to the basic algebraic terminology for the most part (e.g., f²(x) := (f(x))²), and apply all's fair if you predeclare if you intend to use a more esoteric paradigm. So if you want: D²(x) + 2D(x) + x to mean: (D(D(x)) + 2 * D(x) + x You should say: use linearAlgebra; D²(x) + 2D(x) + x -- Jonathan Dataweaver Lang
Re: Musings on operator overloading
HaloO, Larry Wall wrote: likewise, should these be parsed the same? $a**2i $a**2.i and if so, how to we rationalize a class of postfix operators that *look* like ordinary method calls but don't parse the same. This is a conceptual problem that .blahh is visually nailed down on the top precedence by the dot whereas it actually comes in as additional information about i. There's the same problem with foo 1 + 3; # (foo 1) + 3 or foo (1 + 3) which can only be decided by information about foo. 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
On Wed, Mar 26, 2008 at 07:43:16PM +0100, TSa wrote: HaloO, Larry Wall wrote: That's what I thought. Now note that ! can't easily be rewritten as a simple binary operator (unless you do something recursive, and then it's not simple). Would $x! == [*]1..$x constitute simple parserwise? Admittedly it's not a single but two ops and one of them a meta. I meant there's no $x!0 corresponding to 0-$x in the prefix:- rewrite. Now, I think I know how to make the parser use precedence on either a prefix or a postfix to get the desired effect (but perhaps not going both directions simulatenously). But that leads me to a slightly different parsing question, which comes from the asymmetry of postfix operators. How are postfix operators asymmetric? Prefix ops can be followed by whitespace, while postfix may not be preceded by whitespace. Also, the presence of sigils makes it less likely to need space on the front unless you use an alphabetic prefix operator on something starting alphanumeric: abs 1-$x The asymmetry is essentially that we can't just write 1-$x abs without parsing abs as an infix rather than a postfix. (And please don't suggest parsing infixes with optional nullterms on the right; we tried that once, and it screws up the term/infix expectations rather badly.) Larry
Re: Musings on operator overloading
On Wed, Mar 26, 2008 at 12:03 PM, Larry Wall [EMAIL PROTECTED] wrote: On Wed, Mar 26, 2008 at 11:00:09AM -0700, Jon Lang wrote: : all unary operators, be they prefix or postfix, should be evaluated : before any binary operator is. And leaving the pool of voting mathematicians out of it for the moment, how would you parse these: sleep $then - $now not $a eq $b say $a ~ $b abs $x**3 Those don't strike me as being unary operators; they strike me as being function calls that have left out the parentheses. Probably because they're alphanumeric rather than symbolic in form. These all work only because unaries can be looser than binaries. And Perl 5 programmers will all expect them to work, in addition to -$a**2 returning a negative value. True enough. Perhaps I should have said as a rule of thumb... And we have to deal with unary precedence anyway, or !%seen{$key}++ doesn't work right... Larry -- Jonathan Dataweaver Lang
Re: Musings on operator overloading
On Wed, Mar 26, 2008 at 3:18 PM, Jon Lang [EMAIL PROTECTED] wrote: Those don't strike me as being unary operators; they strike me as being function calls that have left out the parentheses. At least through Perl5, 'tain't no difference between those two in Perl land. As for binary !, you could say posit that the second operand is the degree of multifactorialhood, defaulting to 1; e.g. x!2 for what mathematicians would write as x‼, which definitely does not mean (x!)!. Dadgum mathematicians, always messing things up. Can't y'all go back to APL and leave the rest of us alone? :) Oh, and I've always mentally filed -x as shorthand for (-1*x); of course, that's an infinitely recursive definition unless -1 is its own token rather than '-' applied to '1'. Maybe I should have adopted dc(1)ese and spelled it _1. -- Mark J. Reed [EMAIL PROTECTED]
Re: Musings on operator overloading
Mark J. Reed wrote: Jon Lang wrote: Those don't strike me as being unary operators; they strike me as being function calls that have left out the parentheses. At least through Perl5, 'tain't no difference between those two in Perl land. True enough - though the question at hand includes whether or not there should be. Perhaps a distinction should be made between prefix and postfix. After all, postfix already forbids whitespace. True, the original reason for doing so was to distinguish between infix and postfix; but it tends to carry the implication that postfix operators are kind of like method calls, while prefix operators arekind of like function calls. Personally, I'd like to keep that parallel as much as possible. Unless it can be shown to be unreasonable to do so. :) As for binary !, you could say posit that the second operand is the degree of multifactorialhood, defaulting to 1; e.g. x!2 for what mathematicians would write as x‼, which definitely does not mean (x!)!. Wouldn't that be x ! 2? Mandatory whitespace (last I checked), since infix:! had better not replace postfix:!. Oh, and I've always mentally filed -x as shorthand for (-1*x); of course, that's an infinitely recursive definition unless -1 is its own token rather than '-' applied to '1'. It's also only guaranteed to work if x is numeric; even in math, that's not certain to be the case. :) -- Jonathan Dataweaver Lang
Re: Musings on operator overloading
Larry Wall wrote: On Wed, Mar 26, 2008 at 12:56:08PM -0600, Thom Boyer wrote: Larry Wall wrote: ... In the limit, suppose some defines a postfix say looser than comma: (1,2,3)say 1,2,3say 1,2,3.say I must be missing something. Wouldn't it be easier to write 1,2,3 say since say was defined to bind looser than comma? Then you wouldn't need a nospace unspace. The part of Perl 6 that bothers me most is the whitespace dwimmery that required unspace in the first place. I'd hate to see more of it. Not that I have a better solution than the proposed whitespace dwimmery, mind you. How would you keep infix operators in a separate namespace from postfix then? As soon as someone defines infix:++ you're hosed, or we have to throw out all term/infix distinctions that Perl has always had. How would you parse $x ++ /foo/; It also completely destroys the current absolute distinction between say(1 + 2), 3 say (1 + 2), 3 Larry Yup. You gotta have some way to resolve those problems, and the whitespace distinction does the job. And, as I said, I don't have a better solution. But that doesn't obviate my unease with whitespace being so very significant to the meaning of a program. Perhaps it comes from exposure to Fortran IV at an impressionable age -- a language in which nothing changes if you remove ALL whitespace (outside of Hollerith constants, that is). It might be fair to liken that exposure to the effects of Thalidomide: perhaps my brain's been deformed. But it's only an unease, and I recognize that it's a bias I acquired by programming in so many different languages in which whitespace is insignificant. I further recognize that Perl offers a lot of way-cool stuff that wouldn't be possible with out whitespace dwimmery. I *love* list operators. Being able to write, in Perl 5, foreach_vertex $polygon, sub { # executed once for each vertex, with the vertex in $a print point #, $n++, : $a\n; }; instead of foreach_vertex($polygon, sub { # executed once for each vertex, with the vertex in $a print point #, $n++, : $a\n; }); makes a world of difference to readability. And I'd be *tempted* to resolve the the ambiguity in say (1 + 2), 3 by treating that as say(1+2), 3 and requiring (function-call, not list-operator) syntax like say((1+2), 3) if you want the other. But that would have a horrible effect. If I started with say $x*2, 3 and then realized I needed to add one to $x before doubling, I'd be surprised by the resulting treatment of say ($x+1)*2, 3 So you made the right call there, in my opinion. The whitespace makes clear the programmer's intent, once you're used to list operators. As for: $x ++ /foo/; well, for that case, I can't even think of a BAD suggestion to make, so whitespace dwimmery is again the best solution I know. And yet that whitespace-is-insignificant meme keeps tickling my brain. And what really cranked it up to poison-ivy level was the unspace. I can't even explain why. I don't even *understand* why, myself, so I can hardly speak on the subject in a cogent manner. I suspect it's an emotional, irrational, reaction. I probably just need to just scratch the inside of my skull with a wire brush until the itch is gone. And quit bothering the list with my idiosyncrasy. After all, it's an entirely artificial idea in the first place -- because, to humans, whitespace really DOES matter; it's only those stupid compilers that feel otherwise. - But the main point I was trying to make is just that I didn't see the necessity of positing 1,2,3\say when (if I understand correctly) you could write that as simply as 1,2,3 say And if someone really wants to apply a Ct postfix operator in a string interpolation, then let them say say blah {$x t} blah That seems better to me than saying that there's no tab character in say blah $x\t blah Backslashes in double-quotish contexts are already complicated enough! =thom
Re: Musings on operator overloading
Thom Boyer wrote: But the main point I was trying to make is just that I didn't see the necessity of positing 1,2,3\say 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:say operator. That seems better to me than saying that there's no tab character in say blah $x\t blah Whoever said that? Backslashes in double-quotish contexts are already complicated enough! ...and they'd remain precisely as complicated as they are now, because backslashes in interpolating quotes and in patterns would continue to behave precisely as they do now. Backslash-as-unspace would remain unique to code context, as it is now, changing only in that it gets followed by \s* instead of \s+. In particular, if you were to define a postfix:t operator, you'd embed it in a string as: say blah {$x\t} blah -- Jonathan Dataweaver Lang
Re: Musings on operator overloading
HaloO, Larry Wall wrote: Another minor psychological factor is comes into play is that, besides being too hard to type, ÷ is visually a symmetrical operator, while division is inherently an asymmetric operation. You'll notice that other asymmetric operators invented by mathematicians tend to convey that asymmetry visually. OK, with symmetric equal to commutative. But you don't have this concern with - which is as asymmetric as /. Also x and xx are asymmetric without visual indication. These are not even symmetric in the types of their operants. : Second, a path is much more like a string than a number. : : Right. Which means there's no room for confusion with division, : 'cause you can't divide strings! Ambiguity gone, problem solved, no : worries. Er, except for hordes of Perl 5 programmers who think you can... :) Yeah! We could actually invent x/ for a inverse operation of x in the sense that you factor a string. E.g. 'aaa' x/ 3 eq 'a' but 'abc' x/ 3 eq ''. That is a non-repetitive string is kind of primal. Hmm, or x/ behaves more like % and 'abc' x/ 3 eq 'abc' and 'aaa' x/ 2 eq 'a' and of course 'aaa' x/ 3 eq ''. But that might better be spelled x%, I think. Speaking of x actually makes me wonder about two things in its definition: (1) why is it non-associative and (2) why is it not on the multiplicative precedence but below addition? It could be made left associative: 'ab' x 3 x 2 eq 'abababababab' which implies that 3 x 2 == 6. So we would get a multiplication operator that the optimizer wouldn't touch commutatively. Hence it would be a good candidate for the vector cross product and quaternion multiplication and such. Or we could use it for the scalar multiplication of vectors. That would require it to be commutative, though. Note that this is no problem if we define infix:x:(::T,::T) to be a type error whilst infix:x:(::T, Num | Num, ::T) allows 3 x 'a' eq 'a' x 3 eq 'aaa' when ::T === Str. Actually we could make x commutatively list associative and define that at most one operant can be of a type different from Num or better a type that is a Field, e.g. Complex. This automatically gives (1,2,3) x 3 === 3 x (1,2,3) === (2,6,9). Uhh, and ~~ might check linear dependence of vectors or so. BTW, how would the signature of x look like if you want to enforce the presence of at most one argument of type Field? The problem is you can't have the variadic array at the front or the middle to get multi *listfix:x ( none(Field) ::T $v, Field [EMAIL PROTECTED] | Field [EMAIL PROTECTED], none(Field) ::T $v| Field [EMAIL PROTECTED], none(Field) ::T $v, Field [EMAIL PROTECTED] -- T) {...} perhaps multi *listfix:x ( [EMAIL PROTECTED] where { one(@scalars) does none(Field) or all(@scalars) does Field } ) {...} but that makes capturing the non-field type impossible. An additional idea of mine is to also introduce a generic multiplication operator infix:o as ASCII equivalent of U+2218. An exponentiation in terms of o would be written oo. That somewhat makes xx oddly overloaded with list replication where one could expect it to be exponentiation in terms of x. Then again scalar multiplication has no exponential form. For geometric algebra one would introduce _| (U+2A3C) and |_ (U+2A3D) for left and right contraction and /\ for the wedge. And then choose x for the geometric product if it had multiplicative precedence. Or if we follow the scalar multiplication approach outlined above, infix:*:(::T, T -- T) would become a generic list associative non-commutative product operator. Note that a proper product is homogeneous in ::T whereas multiplicative x is generally not. Sorry if this is off-topic, but this is the outcome if I'm musing about operator overloading. My driving idea is to abstractly define the properties of operators that should hold when overloaded. E.g. + for string concatenation is bad because I would expect $a + $b eqv $b + $a. From the commutativity point of view it could be argued to overload - which isn't commutative like ~. But I've never seen - being overloaded with string concatenation ;) In the last section of S03 good names for the three groups of operators are asked for. I would call the group with guaranteed sequence points just that: sequential operators. They come in two types: left and right sequential. Basically this replaces the wrong usage of associativity of an operator. Then associativity could retain its mathematical meaning and allow the optimizer/parallizer to group at will. E.g + would be associative but - left-sequential or forcing associative addition with prior unary -. Same thing with * and / if we have e.g. prefix:1/ applied before associating the factors. Commutativity would be an even better property of an operator because it doesn't have to assemble values returned from multiple threads in the order prescribed
Re: Musings on operator overloading
HaloO, Doug McNutt wrote: Don't allow it to become = f(-$x); ## wrong! Unless of course f does Linear, then you can factor out or in the multiplication with -1 at will. So linearity of operators and functions is a very interesting property for optimizers. 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
* TSa [EMAIL PROTECTED] [2008-03-19 16:00]: Aristotle Pagaltzis wrote: Something like path { $app_base_dir / $conf_dir / $foo_cfg . $cfg_ext } where the operators in that scope are overloaded irrespective of the types of the variables (be they plain scalar strings, instances of a certain class, or whatever). Assuming there are Path, Extension, Directory and File types, the better approach would be in my eyes to overload string concatenation. That presumes you will never want non-path concatenation semantics on filesystem path values. Then how do I write `die Couldn't open $abspath: $!\n`? When you leave the broader domain of mathematical and “para-” mathematical abstractions behind and start to define things like division on arbitrary object types that model aspects of domains which have nothing even resembling such concepts, you’re rapidly moving into the territory of obfuscation. Indeed mathematics is all about distilling abstract properties from problem domains and then proving abstract theorems. That means when applying mathematics you only have to meet the preconditions and get all consequences for free. But overloading a symbol that means product with something that does not adhere to the algebraic properties of products is a bad choice. Which was my point. Note that even with mathematical abstractions, there are cases where scope-bound overloading is a win over type-bound overloading. Consider a hypothetical Math::Symbolic that lets you do something like this: my $x = Math::Symbolic-new(); print +( $x**2 + 4 * $x + 3 )-derivative( $x ); I hope it’s obvious how such a thing would me implemented. No, I find that far from obvious. Time to read up on operator overloading then. :-) When I say “hypothetical” I mean merely in the sense that “it doesn’t exist on the CPAN in this form” – I did not imply that this would require anything outside the currently available semantics. Kragen Sitaker wrote that precise library in Python 2.x; it could easily be recreated in Perl 5. Your derivative method should have type :(Code -- Code) No. There are no code blocks or parse trees anywhere in sight, only an expression representation built up the Math::Symbolic object internally as its methods for the various overloaded operations were called. Now, if you used type-bound overloading, then the following two expressions cannot yield the same result: ( 2 / 3 ) * $x 2 * $x / 3 But if overloading was scope-bound, they would! First of all I would allow the optimizer to convert the latter into the former unconditionally. […] Hmm, thinking twice, the above optimization is admissible only if multiplication is commutative irrespective of the type of $x. Exactly. I think your statement makes only sense when the polymorphism on the type of $x is dropped in scope-bound overloading. That’s what I was talking about all along: a way to overload operators monomorphically for the duration of a scope. Operators in Perl are monomorphic, as a rule of thumb. String concatenation requires that you use the string concatenation operator, not the addition operator overloaded by the string type to mean concatenation. So I’d like directory-scope path qualification to have its own operator; what the `path {}` syntax does is override the operator bound to the slash and dot symbols for the duration of the block, regardless of the type of operands they operate on. In other words $x is then always converted into the suitable form. Yes. That’s exactly how Perl already works. You say `$x + $y`, it converts $x and $y into numbers somehow. You say `$foo eq $bar`, it stringifies $foo and $bar in whichever way it can. You say `if ( $quux )` and it boolifies $quux in whatever way it knows to do so. Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/
Re: Musings on operator overloading
* Mark J. Reed [EMAIL PROTECTED] [2008-03-19 20:45]: Maybe it's just 'cause I cut my teeth on BASIC, but + for string concatenation has always felt pretty natural. Obviously it won't work in Perl where you are using the operator to determine how to treat the operands. At first blush I find it more readily readable than or ||, or even .. Personally, after getting thoroughly used to Perl, I always have a vague feeling of unease in languages where I need to use + to concatenate. It makes the meaning of the statement dependent on the types of any variables, which is information that a reader won’t necessarily find in close vicinity of the statement. And that’s exactly what led me to the idea I proposed in the initial mail in this thread – changing the meaning of an operator from one monomorphic operation to another within a lexical scope. Hopefully, the new meaning is somewhat related to the original - a sort of operator metonymy - but if the context is sufficiently different, that's not a requirement. Again, nobody's going to think you're dividing pathnames. Strongly disagree. If context was sufficient to help the reader, how did operator overloading get such a bad rep in C++? That’s exactly what my proposal was all about: if you’re completely changing the meaning of an operator, the reader should have nearby indication of what is really going on. Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/
Re: Musings on operator overloading
On Fri, Mar 21, 2008 at 4:25 PM, Aristotle Pagaltzis [EMAIL PROTECTED] wrote: It makes the meaning of the statement dependent on the types of any variables, which is information that a reader won't necessarily find in close vicinity of the statement. [...] if you're completely changing the meaning of an operator, the reader should have nearby indication of what is really going on. Ah, so you want the types of typed vars to be apparent where those vars are used. Well, there's an easy solution there: Hungarian notation! (ducks under barrage of rotten fruit) -- Mark J. Reed [EMAIL PROTECTED]
Re: Musings on operator overloading
* Mark J. Reed [EMAIL PROTECTED] [2008-03-21 21:35]: On Fri, Mar 21, 2008 at 4:25 PM, Aristotle Pagaltzis [EMAIL PROTECTED] wrote: It makes the meaning of the statement dependent on the types of any variables, which is information that a reader won't necessarily find in close vicinity of the statement. [...] if you're completely changing the meaning of an operator, the reader should have nearby indication of what is really going on. Ah, so you want the types of typed vars to be apparent where those vars are used. Well, there's an easy solution there: Hungarian notation! (ducks under barrage of rotten fruit) The other easy solution is monomorphism, wherein the types of the variables are irrelevant. It so happens that this is what Perl does and what my proposal was about. Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/
Re: Musings on operator overloading
On 2008-Mar-19, at 1:40 pm, Mark J. Reed wrote: On Wed, Mar 19, 2008 at 1:01 PM, Larry Wall [EMAIL PROTECTED] wrote: The use of + in Python or in C++ is, I think, primarily the violation of a *linguistic* principle, not a mathematical principle. Maybe it's just 'cause I cut my teeth on BASIC, but + for string concatenation has always felt pretty natural. That's because it is natural. Kids don't have to be very old to get the joke in 1+1=11. People just naturally think of plus or a plus- sign as a synonym for and. In a non-technical context, I bet we all scribble down '+'s on notes and grocery lists, etc. to stand for any of Perl's: + ~ , ; . It's not that there isn't ambiguity, but it's an ambiguity that we're used to dealing with in everyday life, so it maps easily onto a programming language. Not that I'm saying separate operators are a bad thing. When programming, we do often have to mix numbers and strings in all sorts of ways, so Perl's + and ~ are often a better match for the problem- space. It may require marginally more effort to get used to than BASIC's dual-purpose +, but I'm not sure even that's true, since we really are used to distinguishing addition from concatenation, even in grocery lists -- it's just that we humans are a lot better about understanding context than machines are, so we implicitly translate plus signs into one or the other on the fly. (Actually, Perl6 allows for context in a way that earlier Perls didn't: you can declare something to be a Num or a Str, and then a single overloaded + would work; in the old days when scalars had split personalities, you needed to specify the type some other way -- in the operator. Interestingly, BASIC has gone the other direction -- at least, Visual BASIC uses + for addition and for concatenation; I'm guessing this happened when VB got variant types that could hold either numbers or strings.) While I agree with the sentiment of not arbitrarily restricting people from doing ugly things unless they ask for such restrictions, Agreed... though I disagree that the sort of overloading under discussion (/ for separating paths) falls into the ugly things category. It's not ideal, but it's a fact of life. Slashes for path separators are such a widespread custom that it would make as much sense to give up slashes for division. (Actually, it would make more sense to keep slashes for paths and switch to ÷ (U+00F7) because the real division sign is at least as widespread for division, and isn't ambiguous in all the other ways slashes are, such as random separators on grocery lists.) Whereas it is common to find addition and concatenation in the same expression, it's very uncommon to find division and path-building going on at the same time. Path-building plus string-concat'ing *is* a likely and reasonable combination, though, so I would be against using ~ for joining paths. (It is tempting to want a leading / to start an absolute path, and ./ to introduce a relative path, but those are ambiguous with regex delimiters and a $_ method. (Although ./ could probably work by the longest-token rule?) However, it's not a hardship to do something like: io $foo/$bar, or io /$foo/$bar, where io() is an IO-object constructor -- those example thus being: io($foo) / $bar, or io() / $foo / $bar.) The typical user already has a good notion of what the common operators are, and what they mean. So while drastically changing the meaning of one of those operators may not be a disservice to the writer of the code, it may well be a disservice to the reader. Which is why I hope P6 defines standard symbols in the standard way. (Where by standard I mean symbols that have a well-defined popular meaning, e.g. ÷, ≤, ∈, ±, ¬. Well, and a meaning that's useful to Perl... ♂ and ♀ are well-defined, but I don't know how you'd use them in P6. (I guess they could be enums!)) I agree *changing* the meaning is bad. But the Good Kind of operator overloading doesn't do that; it just adds a new meaning. It really is overloading. Yup, again because overloading is natural to human communication. And of course being so flexible about how to balance mapping onto the way humans think vs. mapping onto the problem space is what makes P6 so delightful. Which is why I like it so much more than certain of its brethren with their Orthogonality Ueber Alles attitude. I just don't want to see that sort of prescriptivity creep in to Perl. (Unless it's predeclared, of course!!) -David
Re: Musings on operator overloading
On Thu, Mar 20, 2008 at 2:24 AM, David Green [EMAIL PROTECTED] wrote: Interestingly, BASIC has gone the other direction -- at least, Visual BASIC uses + for addition and for concatenation; I'm guessing this happened when VB got variant types that could hold either numbers or strings. Actually, VisualBASIC (at least as of VB.NET/2008) still has + for concatenation, too. is preferred because of the complex set of rules that determine when + does conversions and when it doesn't (for instance, adding a stringish Object to a numeric Object wll in some cases convert the string to a number and add instead of concatenating!), but + still works. -- Mark J. Reed [EMAIL PROTECTED]
Re: Musings on operator overloading
HaloO, Mark J. Reed wrote: For the record, I am opposed to any restriction on operator overloading that requires mathematical properties to hold. ANYTHING is fair if you predeclare. Hmm, my idea is more about defining interfaces that allow to detach implementation of (numerical) algorithms from datatypes. E.g. the Euclidean algorithm to find the gcd requires division and a remainder that decreases in absolute value. This is like sorting objects that do the Ordered role. Besides, there is nothing that inherently associates the / symbol with division - it's only an ASCII approximation of fraction notation. We all know that ASCII is a rather limited char set but one that has the widest support. Unicode has got U+2215 and U+2044 for division and fraction composition. I want to be able to define / as a path constructor and not give a flying flip that (path 2) * (path 3) / (path 5) - whatever the heck * might mean on paths - is not the same as (path 2) / (path 5) * (path 3). We need to distinguish two fundamentally different things here. Symbol overloading which is a parser feature and operator overloading that is runtime dispatch unless the compiler has enough information to avoid it. Using / for paths has several drawbacks. First, it is not the universal directory separator, \ is in widespread use also. Second, a path is much more like a string than a number. Third, you have to make sure that at least one of the concatenated types is a Path so that you are dispatching to the intended implementation. Instead of overloading ~ for paths I think inventing ~/ or ~\ as path concatenating operators is well in line with the Perl 6 operator set. And ~. could be the extension concatenator. And I also feel that overloading ~ for file concatenation or photo stitching is good practice. BTW, operator overloading does not allow to change the precedence, associativity and commutativity of the operator because these are parser features. We already had the issue of overloading / with div for Int operants. And IIRC the conclusion then was that / is a Num operator and thus 2/3 != 0 but 2/3 == 0.. The P in Perl stands for Practical, not Pedantic. I consider well designed interfaces as practical not pedantic ;) 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
On Thu, Mar 20, 2008 at 10:01 AM, TSa [EMAIL PROTECTED] wrote: Hmm, my idea is more about defining interfaces that allow to detach implementation of (numerical) algorithms from datatypes. E.g. the Euclidean algorithm to find the gcd requires division and a remainder that decreases in absolute value. This is like sorting objects that do the Ordered role. Sure. But that's different from saying Ok, you can only define an / operator for numberish things. Besides, there is nothing that inherently associates the / symbol with division - it's only an ASCII approximation of fraction notation. We all know that ASCII is a rather limited char set but one that has the widest support. Unicode has got U+2215 and U+2044 for division and fraction composition. Not to mention good old ÷, which is even in Latin-1. Using / for paths has several drawbacks. First, it is not the universal directory separator, \ is in widespread use also. Meh. Even on Windows you can use / everywhere in the API, and Windows folks are used to seeing the forward slash used this way in URLs if nothing else. Mac OS X uses POSIX paths under the covers, and we sure aren't going to get the colon for this anyway... Second, a path is much more like a string than a number. Right. Which means there's no room for confusion with division, 'cause you can't divide strings! Ambiguity gone, problem solved, no worries. Third, you have to make sure that at least one of the concatenated types is a Path so that you are dispatching to the intended implementation. Yes, I was sort of assuming there'd be a simple constructor for that. Maybe even a lexically-enablable path literal syntax. #P... anyone? :) Instead of overloading ~ for paths I think inventing ~/ or ~\ as path concatenating operators is well in line with the Perl 6 operator set. And ~. could be the extension concatenator. I would be pretty happy with ~/ and ~. Especially if we also got unary ~/ for making absolute paths in a natural fashion. And I also feel that overloading ~ for file concatenation or photo stitching is good practice. File concatenation, maybe; photo stitching is inherently a more complex operation than concatenation. Overloading ~ for that would be, in my mind, analogous to overloading * for vectors: there's more than one way to do that, so which operation does it mean? BTW, operator overloading does not allow to change the precedence, associativity and commutativity of the operator because these are parser features. That depends on the degree to which you can munge the parser, though. And I got the impression that in Perl6 the parser is pretty mungible. You just have to get to it early enough... We already had the issue of overloading / with div for Int operants. And IIRC the conclusion then was that / is a Num operator and thus 2/3 != 0 but 2/3 == 0.. What I'd really like (blue skies, smiling at me...) to see come back from / is a sort of abstract result-of-division object, which you can then extract what you want out of it: quotient as float, quotient as integer, modulus, list containing the latter two, rational fraction, whatever. Of course, it should automatically Numify to some default, probably the floating point quotient, and be optimized to yield that directly when the parser can figure out that it can do that... The P in Perl stands for Practical, not Pedantic. I consider well designed interfaces as practical not pedantic ;) Of course, good design is extremely practical. Just not necessarily objectively measurable. :) -- Mark J. Reed [EMAIL PROTECTED]
Re: Musings on operator overloading
HaloO, Mark J. Reed wrote: Sure. But that's different from saying Ok, you can only define an / operator for numberish things. Well, if you adhere to the ring, field or whatever interface the overloaded / sort of ends up being numberish anyway. BTW, do we have a unary multiplikative inversion operator? That is 1/ as prefix or **-1 as postfix? Perhaps .inv as method? Do we have .neg for additive inversion? Right. Which means there's no room for confusion with division, 'cause you can't divide strings! Ambiguity gone, problem solved, no worries. But without contextual information about the type of $x and $y an expression $x/$y doesn't look particularly stringish to me. BTW, operator overloading does not allow to change the precedence, associativity and commutativity of the operator because these are parser features. That depends on the degree to which you can munge the parser, though. And I got the impression that in Perl6 the parser is pretty mungible. You just have to get to it early enough... But you can't mix the two concepts! Consider sub foo ($x) { return $x + $x * $x; } and imagine a type Blahh that behaves like Num but swaps precedence of + and *: my Blahh $y = 3; say foo($y); # == 18 say foo(3); # == 12 How should the dispatcher know to dispatch to + first for $y? 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
On Thu, Mar 20, 2008 at 11:03:11AM -0400, Mark J. Reed wrote: :Besides, there is nothing that inherently :associates the / symbol with division - it's only an ASCII :approximation of fraction notation. : : We all know that ASCII is a rather limited char set but one : that has the widest support. Unicode has got U+2215 and U+2044 : for division and fraction composition. : : Not to mention good old ÷, which is even in Latin-1. At this point in our history, slash for division is so ingrained into the culture that it would be very difficult to change without widespread grumbling. People have a hard enough time accepting things the extra typing of «+», and I suspect we get away with that only because the user feels the construct is very powerful, and hence worth the agony. Huffman coding can be tweaked in several ways, and power / cost might be one of them. Division is perceived as a very basic operation, so not worth much cost to type. Another minor psychological factor is comes into play is that, besides being too hard to type, ÷ is visually a symmetrical operator, while division is inherently an asymmetric operation. You'll notice that other asymmetric operators invented by mathematicians tend to convey that asymmetry visually. And even with division, the notion of over is asymmetrical, which / is of course proxying for. But perhaps the overriding reason to avoid ÷ is that it's perceived as something that's only used in grade school that you grow out of. : Using / for paths has several drawbacks. First, it is not : the universal directory separator, \ is in widespread use also. : : Meh. Even on Windows you can use / everywhere in the API, and Windows : folks are used to seeing the forward slash used this way in URLs if : nothing else. Mac OS X uses POSIX paths under the covers, and we sure : aren't going to get the colon for this anyway... Well, then there's VMS... :) : Second, a path is much more like a string than a number. : : Right. Which means there's no room for confusion with division, : 'cause you can't divide strings! Ambiguity gone, problem solved, no : worries. Er, except for hordes of Perl 5 programmers who think you can... :) : Third, you have to make sure that at least one of the concatenated types is a Path so that : you are dispatching to the intended implementation. : : Yes, I was sort of assuming there'd be a simple constructor for that. : Maybe even a lexically-enablable path literal syntax. #P... anyone? : :) Been trying to avoid tokens that start with # to keep the parsing rules simple...er, less complex... We don't even allow # for user-defined quotes any more, since it's legal to have whitespace (and hence, a comment) between the q and the quote char. But I'd suggest that path() would be much more readable, and Path() is already a built-in coercion if you have a Path type. And how often do you really type path literals? And maybe it would better be handled by some kind of url-ish string that gets mapped to the local conditions transparently. Or just use arrays, which are much more convenent for directory tree traversals, and convert to path at the last moment. : Instead of overloading ~ for paths I think inventing ~/ or ~\ as : path concatenating operators is well in line with the Perl 6 operator : set. And ~. could be the extension concatenator. : : I would be pretty happy with ~/ and ~. Especially if we also got : unary ~/ for making absolute paths in a natural fashion. Those would work, though I wouldn't exactly call 'em pretty... Nice visual correspondence though. I'd even let you have ~: for the drive. :) : And I also feel that overloading ~ for file concatenation or photo stitching is good practice. : : File concatenation, maybe; photo stitching is inherently a more : complex operation than concatenation. Overloading ~ for that would : be, in my mind, analogous to overloading * for vectors: there's more : than one way to do that, so which operation does it mean? At some point it becomes silly to define an operator when you can just say mystitch(@pix). : BTW, operator overloading does not allow to change the precedence, : associativity and commutativity of the operator because these are : parser features. : : That depends on the degree to which you can munge the parser, though. : And I got the impression that in Perl6 the parser is pretty mungible. : You just have to get to it early enough... Not disagreeing with either of you, but more in the way of an explication... You can add or change operator syntax in Perl 6, but such changes are mandatorily lexically scoped, as are all macros and grammatical tweaks. It's quite possible for a given operator parser to adjust its own precedence and associativity on the fly. Indeed, the assignment operator has to decide at parse-time, based on its left argument, whether its precedence is that of an item assignment or a list assignment. What you guys
Re: Musings on operator overloading
On Thu, Mar 20, 2008 at 05:06:00PM +0100, TSa wrote: BTW, do we have a unary multiplikative inversion operator? That is 1/ as prefix or **-1 as postfix? Well, 1/ looks like a pretty good prefix. :) Except it's not really first class. This ain't Haskell... As for **-1, I'd suspect that of being more approximative than the corresponding division on some architectures. Perhaps .inv as method? I imagine most non-mathematicians would go more for .recip or some such. Do we have .neg for additive inversion? We currently have $num.prefix:- which is admittedly a bit unwieldy. But it's difficult to extend that syntax to reciprocal, since $num.infix:/(1) doesn't work because the args are in the wrong order. If someone *did* define prefix:1/ then you could say: $num.prefix1/ though that probably screws up precedence somehow. But you can't mix the two concepts! Indeed, to the first approximation, the parser pays no attention to the types, and multiple dispatch pays no attention to the syntax. Larry
Re: Musings on operator overloading
At 17:06 +0100 3/20/08, TSa wrote: BTW, do we have a unary multiplikative inversion operator? That is 1/ as prefix or **-1 as postfix? Perhaps .inv as method? Do we have .neg for additive inversion? There certainly is the unary minus even though it is badly interpreted in some languages, thankfully NOT including perl 5. Don't even think about parsing = -$x**2; so that it returns a positive result. Perl 5 handles it by assigning a higher precedence to ** than to addition. The real fact is that the minus sign in the above formula just isn't a unary minus in chalkboard algebra. = $a - $b - f($x); when $a is known to by identically equal to $b should be the same as = 0 - f($x); or just = - f($x); which happens easily with pencil and paper. Don't allow it to become = f(-$x); ## wrong! even if the f() is really written as $x**2 or has some other postfix operation - inversion - that's considered a function by a mathematician. * At 15:01 +0100 3/20/08, TSa wrote: BTW, operator overloading does not allow to change the precedence, associativity and commutativity of the operator because these are parser features. A vector on the chalkboard can be a row or a column but in a computer it's an ordered list with the vertical or horizontal order of the components residing only in the mind of the programmer. Multiplying a vector by a matrix implicitly indicates that the vector is a row. Multiplying a matrix by a vector implies a column vector and the results are quite different. =$vector * $matrix; is probably well handled in a overloading method because the order implies the rowness or columnness of the vector but it could get confused by a parser that has its own ideas about precedence and commutativity. -- -- From the U S of A, the only socialist country that refuses to admit it. --
Re: Musings on operator overloading
On Thu, Mar 20, 2008 at 1:09 PM, Doug McNutt [EMAIL PROTECTED] wrote: Don't even think about parsing = -$x**2; so that it returns a positive result. Okay, going way off on a tangent here, but I don't think the Perl interpretation is quite as obviously correct as you think it is; there's a reason the perlsyn page describes it as possibly surprising. Especially if you use a literal instead of a variable, in which case the '-' might be considered part of the literal token in some languages and preempt operator precedence altogether. In any case, the decision is far from unanimous. Fortran, the original source of the ** operator, agrees with Perl on this front; but COBOL, if asked to COMPUTE the same expression, returns a positive result. ( I know, what do you expect from a business-oriented language...) Ada, AWK, Groovy, Haskell, LSL, Lua, Pascal, Python, Ruby, Scala, and Simula all agree that the result is negative. APL also agrees, and it's arguably the ultimate mathematician's language, but it also just evaluates right to left with no precedence levels. There are also languages like M[UMPS] that similarly lack precedence and just plow through left to right, which yields a positive answer here. Precedenceful languages that return a positive result include ALGOL-68, AppleScript, bash/ksh/zsh (let-arithmetic), bc(1), Eiffel, and SNOBOL. SmallTalk has no unary -, but 0 - x raisedTo: 2 yields a positive answer. The various Basic implementations disagree with each other; Visual Basic (including VB.NET) and LibertyBASIC say it's positive, while Chipmunk says negative. Going back in time to 8-bit days, the BASICs on Commodore, TI, Sinclair, and TRS-80 (model 1 level 2) machines return a negative result, while Apple and Atari return a positive one. I find it particularly interesting that not even all of the BASICs from the same codebase (Microsoft's original Altair release) agree with each other... We now return you to your regularly scheduled Perl 6 mailing list, already in progress. -- Mark J. Reed [EMAIL PROTECTED]
Re: Musings on operator overloading (was: File-Fu overloading)
Hi Jonathan, * Jonathan Lang [EMAIL PROTECTED] [2008-02-24 22:30]: So if I'm understanding you correctly, the following would be an example of what you're talking about: { use text; if $a 49 { say $a } } ...with the result being the same as Perl5's 'if $a gt 49 { say $a }' (so if $a equals '5', it says '5'). Am I following you? If so, I'm not seeing what's so exciting about the concept; all it is is a package that redefines a set of operators for whatever scopes use it. If I'm not following you, I'm totally lost. you’re indeed following me. And it’s indeed not very exciting. And that’s exactly the point. I find that regular, type-based overloading is *very* exciting… but not in a good way. An approach that makes operator overloading an unexciting business therefore seems very useful to me. Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/
Re: Musings on operator overloading
HaloO, Aristotle Pagaltzis wrote: Something like path { $app_base_dir / $conf_dir / $foo_cfg . $cfg_ext } where the operators in that scope are overloaded irrespective of the types of the variables (be they plain scalar strings, instances of a certain class, or whatever). Assuming there are Path, Extension, Directory and File types, the better approach would be in my eyes to overload string concatenation. The only drawback is that one of the operants of ~ has to be e.g. a Path to dispatch to infix:~:(Path, Str -- Path). Subsequent concatenations will continue to dispatch to path concatenation because of the return type. With path and ext being unary casts to Path and Extension we get: path $app_base_dir ~ $conf_dir ~ $foo_cfg ~ ext $cfg_ext; I suspect though that having the object carry the semantics around with it is still going to be preferred. No, the semantics should come from a set of operations that blend together. The object type should be used only to dispatch to specific implementations of these semantics. When you leave the broader domain of mathematical and “para-” mathematical abstractions behind and start to define things like division on arbitrary object types that model aspects of domains which have nothing even resembling such concepts, you’re rapidly moving into the territory of obfuscation. Indeed mathematics is all about distilling abstract properties from problem domains and then proving abstract theorems. That means when applying mathematics you only have to meet the preconditions and get all consequences for free. But overloading a symbol that means product with something that does not adhere to the algebraic properties of products is a bad choice. OTOH, overloading ~ with an operation that behaves like a monoid is a bad idea too when the new operation doesn't feel like concatenation. Actually I would argue that ~ could be overloaded for ints in the sense that 1 ~ 2 == 12 numerically, but I'm unsure how that would be implemented without an intermediate string. A lot of C++ programmers could sing a song about that. Oh yes, not being able to invent new symbols for new operations is a pain. But math itself is not free of such things. E.g. there's no commonly accepted notation for conjugation. Some use an overbar, others a dagger or asterisk postsuperscript. The latter might ask for a unary postscript * which I think is technically possible in Perl 6. But * as a symbol is already heavily overloaded. Note that even with mathematical abstractions, there are cases where scope-bound overloading is a win over type-bound overloading. Consider a hypothetical Math::Symbolic that lets you do something like this: my $x = Math::Symbolic-new(); print +( $x**2 + 4 * $x + 3 )-derivative( $x ); I hope it’s obvious how such a thing would me implemented. No, I find that far from obvious. Your derivative method should have type :(Code -- Code) i.e. it returns {2*$^x + 4} when given {$^x**2 + 4 * $^x + 3}. But I fail to see how the type Math::Symbolic of your $x should instruct the parser to hand over the parse tree to .derivative or some such. Now, if you used type-bound overloading, then the following two expressions cannot yield the same result: ( 2 / 3 ) * $x 2 * $x / 3 But if overloading was scope-bound, they would! First of all I would allow the optimizer to convert the latter into the former unconditionally. Then I think your statement makes only sense when the polymorphism on the type of $x is dropped in scope-bound overloading. In other words $x is then always converted into the suitable form. But how is that performed in general? IIRC, the only generically available form is stringification. Hmm, thinking twice, the above optimization is admissible only if multiplication is commutative irrespective of the type of $x. 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
For the record, I am opposed to any restriction on operator overloading that requires mathematical properties to hold. ANYTHING is fair if you predeclare. Besides, there is nothing that inherently associates the / symbol with division - it's only an ASCII approximation of fraction notation. I want to be able to define / as a path constructor and not give a flying flip that (path 2) * (path 3) / (path 5) - whatever the heck * might mean on paths - is not the same as (path 2) / (path 5) * (path 3). The P in Perl stands for Practical, not Pedantic. On 3/19/08, TSa [EMAIL PROTECTED] wrote: HaloO, Aristotle Pagaltzis wrote: Something like path { $app_base_dir / $conf_dir / $foo_cfg . $cfg_ext } where the operators in that scope are overloaded irrespective of the types of the variables (be they plain scalar strings, instances of a certain class, or whatever). Assuming there are Path, Extension, Directory and File types, the better approach would be in my eyes to overload string concatenation. The only drawback is that one of the operants of ~ has to be e.g. a Path to dispatch to infix:~:(Path, Str -- Path). Subsequent concatenations will continue to dispatch to path concatenation because of the return type. With path and ext being unary casts to Path and Extension we get: path $app_base_dir ~ $conf_dir ~ $foo_cfg ~ ext $cfg_ext; I suspect though that having the object carry the semantics around with it is still going to be preferred. No, the semantics should come from a set of operations that blend together. The object type should be used only to dispatch to specific implementations of these semantics. When you leave the broader domain of mathematical and para- mathematical abstractions behind and start to define things like division on arbitrary object types that model aspects of domains which have nothing even resembling such concepts, you're rapidly moving into the territory of obfuscation. Indeed mathematics is all about distilling abstract properties from problem domains and then proving abstract theorems. That means when applying mathematics you only have to meet the preconditions and get all consequences for free. But overloading a symbol that means product with something that does not adhere to the algebraic properties of products is a bad choice. OTOH, overloading ~ with an operation that behaves like a monoid is a bad idea too when the new operation doesn't feel like concatenation. Actually I would argue that ~ could be overloaded for ints in the sense that 1 ~ 2 == 12 numerically, but I'm unsure how that would be implemented without an intermediate string. A lot of C++ programmers could sing a song about that. Oh yes, not being able to invent new symbols for new operations is a pain. But math itself is not free of such things. E.g. there's no commonly accepted notation for conjugation. Some use an overbar, others a dagger or asterisk postsuperscript. The latter might ask for a unary postscript * which I think is technically possible in Perl 6. But * as a symbol is already heavily overloaded. Note that even with mathematical abstractions, there are cases where scope-bound overloading is a win over type-bound overloading. Consider a hypothetical Math::Symbolic that lets you do something like this: my $x = Math::Symbolic-new(); print +( $x**2 + 4 * $x + 3 )-derivative( $x ); I hope it's obvious how such a thing would me implemented. No, I find that far from obvious. Your derivative method should have type :(Code -- Code) i.e. it returns {2*$^x + 4} when given {$^x**2 + 4 * $^x + 3}. But I fail to see how the type Math::Symbolic of your $x should instruct the parser to hand over the parse tree to .derivative or some such. Now, if you used type-bound overloading, then the following two expressions cannot yield the same result: ( 2 / 3 ) * $x 2 * $x / 3 But if overloading was scope-bound, they would! First of all I would allow the optimizer to convert the latter into the former unconditionally. Then I think your statement makes only sense when the polymorphism on the type of $x is dropped in scope-bound overloading. In other words $x is then always converted into the suitable form. But how is that performed in general? IIRC, the only generically available form is stringification. Hmm, thinking twice, the above optimization is admissible only if multiplication is commutative irrespective of the type of $x. Regards, TSa. -- The Angel of Geometry and the Devil of Algebra fight for the soul of any mathematical being. -- Attributed to Hermann Weyl -- Mark J. Reed [EMAIL PROTECTED]
Re: Musings on operator overloading
On Wed, Mar 19, 2008 at 12:38:48PM -0400, Mark J. Reed wrote: : For the record, I am opposed to any restriction on operator : overloading that requires mathematical properties to hold. ANYTHING : is fair if you predeclare. Besides, there is nothing that inherently : associates the / symbol with division - it's only an ASCII : approximation of fraction notation. I want to be able to define / as : a path constructor and not give a flying flip that (path 2) * (path 3) : / (path 5) - whatever the heck * might mean on paths - is not the same : as (path 2) / (path 5) * (path 3). : : The P in Perl stands for Practical, not Pedantic. While I agree with the sentiment of not arbitrarily restricting people from doing ugly things unless they ask for such restrictions, I'd also like to point out that the desire to maintain consistent symbolic distinctions is not limited to mathematicians. The use of + in Python or in C++ is, I think, primarily the violation of a *linguistic* principle, not a mathematical principle. The typical user already has a good notion of what the common operators are, and what they mean. So while drastically changing the meaning of one of those operators may not be a disservice to the writer of the code, it may well be a disservice to the reader. Perl is about linguistics, and hence is more concerned with successful communication than with pure mathematical platonics. Larry
Re: Musings on operator overloading
On Wed, Mar 19, 2008 at 1:01 PM, Larry Wall [EMAIL PROTECTED] wrote: While I agree with the sentiment of not arbitrarily restricting people from doing ugly things unless they ask for such restrictions, Agreed... though I disagree that the sort of overloading under discussion (/ for separating paths) falls into the ugly things category. I'd also like to point out that the desire to maintain consistent symbolic distinctions is not limited to mathematicians. Absolutely. Or rather, not absolutely. I think absolute consistency is in the same category as absolute orthogonality... too much of a good thing. The use of + in Python or in C++ is, I think, primarily the violation of a *linguistic* principle, not a mathematical principle. Maybe it's just 'cause I cut my teeth on BASIC, but + for string concatenation has always felt pretty natural. Obviously it won't work in Perl where you are using the operator to determine how to treat the operands. At first blush I find it more readily readable than or ||, or even .. And makes sense for the various kinds of appending it is used for in C++, Ruby, etc, but only if you don't look at it and think bit shift. Fortuantely, bit shift isn't a fundamental arithmetic operation in the traditional sense, and the set of people who think that is proportionally smaller. The typical user already has a good notion of what the common operators are, and what they mean. So while drastically changing the meaning of one of those operators may not be a disservice to the writer of the code, it may well be a disservice to the reader. I agree *changing* the meaning is bad. But the Good Kind of operator overloading doesn't do that; it just adds a new meaning. It really is overloading. Hopefully, the new meaning is somewhat related to the original - a sort of operator metonymy - but if the context is sufficiently different, that's not a requirement. Again, nobody's going to think you're dividing pathnames. Perl is about linguistics, and hence is more concerned with successful communication than with pure mathematical platonics. Which is why I like it so much more than certain of its brethren with their Orthogonality Ueber Alles attitude. I just don't want to see that sort of prescriptivity creep in to Perl. -- Mark J. Reed [EMAIL PROTECTED]
Re: Musings on operator overloading
HaloO, Doug McNutt wrote: I really want to use complex numbers, vectors, matrices, and sometimes quarternions. I really want to be able to define or use previously defined operators in a way that I learned in the 50's. I want my compiler to understand when I use vectors in which the components are complex numbers. I want dot and cross product to work. I want to be able to multiply a matrix by a vector and get a polite error message if I try that with impossible arguments. This is all possible with Perl 6 and its type system, I hope. The concept of a vector as an element of a vector space e.g. should be instanciable with complex numbers as coordinates. That is the dot product has type :(Vector[::T], Vector[::T] -- ::T). The type ::T has to do the Num role to be viable for instanciating Vector. E.g. Vector[Str] should give a compile time type error. What I think I learned from those two messages is that it's damnably difficult for a parser to figure out what I'm doing. Perhaps it just isn't worth while. If you mean that the parser understands the semantics of your code, building a parser is indeed in the realm of AI. But for reasonable operator overloading only two things are needed. Firstly a definition what exactly constitutes the type Num algebraically. And Secondly a syntax to make that information machine readable. The definition of Num should be as minimal as possible. E.g. it should not contain the requirement to be totally ordered. Well, Num will actually be ordered and there's a type that does not require it. This could be called Field. That is it defines the presence of +, -, * and / as binary operations and unary -. Interestingly there's no unary /. Other functions like sqrt make use of these operators to iteratively calculate their result. The only additional requirement for a numerical type is thus to provide an absolute value function. So as long as a user defined type Foo provides these five operations the sqrt function should automatically be callable with it! Note further that a template implementation of sqrt should automatically yield the result undef for negative real numbers by detecting diverging absolute value or occurrence of division by zero while iterating. And of course there can be optimized implementations for certain types. I really don't mind informing my compiler in advance about what I want a variable to be treated as. Typedef {}, Dimension () and the like are no problem at all. I don't mind. And I think that would also apply to my scientifically oriented friends. Yes, type annotation allows the compiler to detect errors that would otherwise occur at runtime. Not to mention the fact that no optimization is possible. Well, with the above algebraic approach you can generically optimize 2*$x/3 from the cost of two multiplications to (2/3)*$x which costs one runtime multiplication irrespective of the type of $x. Wouldn't it make life easier for the parser to overload the * operator into a dot product whenever both arguments have been defined as vectors or been returned as vectors by a previous operation? Yes, that is easy doing for the compiler. It simply creates code for a dynamically dispatched operator. But the algebraically pleasing approach needs tensor calculus or Clifford algebras to properly define products of vectors. One could even use ** for a cross product since raising to a vector power is unreasonable. This is a particularly bad idea that plays in the same league as using + for string concatenation. Powering is defined through multiplication. So without a proper product there can hardly be a power operator. Without that you don't have power series either and therefore no higher functions like sine or cosine etc. One could also overload the string replicating x operator to mean cross product when called with two three or seven dimensional vectors. Much better than overloading * for the inner product it might be possible to dwell on the customs to write it as a,b if one can avoid the clash with the non-interpolating string list creator. OTOH the scalar product is just [+](@a »*« @b). A nice idea is to abbreviate that as *+ or +* akin to Einstein's summation convention. Regards, TSa. -- The Angel of Geometry and the Devil of Algebra fight for the soul of any mathematical being. -- Attributed to Hermann Weyl
Musings on operator overloading (was: File-Fu overloading)
[Cc to perl6-language as I think this is of interest] [Oh, and please read the entire thing before responding to any one particular point. There are a number of arguments flowing from one another here. (I am guilty of being too quick with the Reply button myself, hence this friendly reminder.)] * Eric Wilhelm [EMAIL PROTECTED] [2008-02-24 02:05]: # from Aristotle Pagaltzis # on Saturday 23 February 2008 14:48: I find the basic File::Fu interface interesting… but operator overloading always makes me just ever so slightly queasy, and this example is no exception. Is that because of the syntax, the concepts, or the fact that perl5 doesn't quite get it right? It’s a matter of readability. It’s the old argument about, if not to say against, operator overloading: you’re giving `*` a completely arbitrary meaning that has nothing in common in any way with what `*` means in contexts that the reader of the code had previously encountered. Does it help to know that error messages will be plentiful and informative? (Not to mention the aforementioned disambiguation between mutations and stringifications.) It has nothing to do with any of these factors. I get the desire for syntactic sugar, I really do… but looking at this, I think the sane way to accommodate that desire is to attach overloaded semantics to a specially denoted scope rather than hang them off the type of an object. I can't picture that without an example. Something like path { $app_base_dir / $conf_dir / $foo_cfg . $cfg_ext } where the operators in that scope are overloaded irrespective of the types of the variables (be they plain scalar strings, instances of a certain class, or whatever). Note that I’m not proposing this as something for File::Fu to implement. It would be rather difficult, if at all possible, to provide such an interface in Perl 5. You need macros or access to the grammar or something like that in order to implement this at all. Although I think that even if you have those, you wouldn’t want to use them directly, but rather as a substrate to implement scope-attached operator overloading as an abstraction over them. But I think it’s desirable to use this abstraction instead of using grammar modifications or macros directly, since it vastly more limited power than the former and still much less power than the latter. It should therefore be easier both in use by the programmer who designs the overloading scope and in readability for the maintenance programmer who reads code that uses overload scopes. It would particularly help the latter, of course, because the code’s behaviour does not vary based on the types that happen to pass through; the source code is explicit and direct about its meaning. I suspect though that having the object carry the semantics around with it is still going to be preferred. There are cases where it would be. When the object is a mathematical abstraction in some broad sense, e.g. it’s a complex number class, or it implements some kind of container such as a set, then being able to overload operators based on the type of that object would be useful. But note that in all of these examples, it is very much self-evident what the meaning of an overloaded `+` would be: that meaning comes from the problem domain – a problem domain that has the rare property of having concepts such as operators and operands. When you leave the broader domain of mathematical and “para-” mathematical abstractions behind and start to define things like division on arbitrary object types that model aspects of domains which have nothing even resembling such concepts, you’re rapidly moving into the territory of obfuscation. A lot of C++ programmers could sing a song about that. However, I think the way that Java reacted to this (“only the language designer gets to overload operators!!”) is completely wrong. I agree fully with the underlying desire you express: The essential motivation is that if I can't make this interface work, I'm just going to slap strings together and be done with it. The converse is that if I can make this interface work then cross-platform pathname compatibility becomes far less tedious. Absolutely it is very, very useful to be able to define syntactic sugar that makes it as easy and pleasant to do the right thing (manipulate pathnames as pathnames) as it is to do the wrong thing (use string operations to deal with pathnames). That is precisely why I said that I do get why you’d want to overload operators. And this contradiction – that being able to declare sugar is good, but the way that languages have permitted that so far leads to insanity – is what sent me thinking along the lines that there has to be some way to make overloading sane. And we all know that all is fair if you predeclare. And that led me to the flash of inspiration: why not make overloading a property of the source (lexical, early-bound) rather than of the values (temporal, late- bound)? And what
Re: Musings on operator overloading (was: File-Fu overloading)
On 24 Feb 2008, at 15:00, Aristotle Pagaltzis wrote: Something like path { $app_base_dir / $conf_dir / $foo_cfg . $cfg_ext } I've wanted this often. I've also wanted a clean way to lexically supply a default target object. For example with HTML::Tiny you often write my $h = HTML::Tiny-new(); $h-body($h-head($h-title('FooPage')), $h-body(...)); I'd love to be able to drop the '$h-' everywhere. Like this: $h-body( head( title( 'FooPage' ) ), body( ... ) ); I guess that would/could be a related mechanism. -- Andy Armstrong, Hexten
Re: Musings on operator overloading (was: File-Fu overloading)
On Sun, Feb 24, 2008 at 3:00 PM, Aristotle Pagaltzis [EMAIL PROTECTED] wrote: Something like path { $app_base_dir / $conf_dir / $foo_cfg . $cfg_ext } where the operators in that scope are overloaded irrespective of the types of the variables (be they plain scalar strings, instances of a certain class, or whatever). This is excellent. I've long supported the one symbol-one meaning idea. There are some trade-offs, though, which I'll describe. I'll use Haskell as my object language, since it does this sort of operator defining rather than operator overloading (only for infix binary operators though, not full syntactic constructs). Recently I implemented a Vector class in Haskell. Vectors have addition and multiplication, of a sort, so it makes sense to use the + and * operators. In Haskell overloading comes in type classes, where the operators you overload need to have specific types and you also have an implicit contract to obey some laws about them when you overload. In the context of Perl, types don't mean squat, but the implicit laws are still important, so this argument still applies. The Num class for these operators looks like this: class Num a where (+) :: a - a - a -- take 2 arguments of type a and return 1 of type a (*) :: a - a - a ... Which means that if I wanted to overload (+) to work on vectors, my (+) would have to have type Vector - Vector - Vector. That's fine, it is that type. And it's associative and commutative as the class expects. The trouble is with (*). There are three types of multiplication on vectors, with these types: Double - Vector - Vector Vector - Double - Vector Vector - Vector - Double -- inner product None of which is Vector - Vector - Vector as Num is expecting. Now, not letting me overload (*) was a good idea on Num's part. Normally if you have some v in Num, you can say (v*v) + v and it will be legal. But if v were a vector, then this wouldn't work, you'd end up trying to add a scalar and a vector. It's very simple, Vectors are not Nums in the sense that the class requires The way I solved this was to create my own class with special vector operations, so the user of the module had to differentiate between vector operations and scalar operations. class Vector v where (^+^) :: v - v - v (*^) :: Double - v - v (^*^) :: v - v - Double x ^* y = y *^ x x ^-^ y = x ^+^ (-1) *^ y Which could be construed as annoying. This problem could have been ameliorated in another way, namely to have designed Num differently. If Num separated the notions of addition and multiplication, or even had been designed as a Vector space in the first place, then I could have used + and * like I wanted to. But it wasn't, so I couldn't. More below. I hope it's obvious how such a thing would me implemented. Now, if you used type-bound overloading, then the following two expressions cannot yield the same result: ( 2 / 3 ) * $x 2 * $x / 3 But if overloading was scope-bound, they would! And here is why you need ad-hoc overloading in addition to scope-based overloading. There are times when I mean 2/3 4 to mean the symbolic data structure representing that condition, and there are other times when I just want to check whether 2/3 is less than 4! Here's a contrived example: my $expr = 1; my $count = 1; while ($count 10) { print $count $expr\n; $expr = $expr + $expr; $count = $count + 1; } With the intention of printing something like: 1 1 2 1 + 1 3 (1 + 1) + (1 + 1) ... Which is, of course, broken. I would have to do something crazy with scopes: while ($count 10) { print $count $expr\n; $expr = do { use Math::Symbolic; $expr + $expr }; $count = $count + 1; } Which could also be construed as annoying. However, here $count + 1 and $expr + $expr are the same +. They both mean add. Why should I have to play with scopes for this. Contrast this with Java, where 3 + 4 and hello + world are different +s (unless you're used to thinking about monoids). Getting those two to coexist is the thing that should require playing with scopes (or better yet, using diffrent symbols for the two of them). I do think the best solution is a combination of overloading and scoping. That is, allow operator overloading, but not overloading the name +, rather overloading a specific +, such as Math::infix:+. This still allows poor usage as we've commonly seen with operator overloading. But it also allows well-behaved usage, which was previously forbidden. Luke
Re: Musings on operator overloading (was: File-Fu overloading)
On Sun, Feb 24, 2008 at 04:23:54PM +, Andy Armstrong wrote: I've wanted this often. I've also wanted a clean way to lexically supply a default target object. For example with HTML::Tiny you often write my $h = HTML::Tiny-new(); $h-body($h-head($h-title('FooPage')), $h-body(...)); I'd love to be able to drop the '$h-' everywhere. Like this: $h-body( head( title( 'FooPage' ) ), body( ... ) ); I guess that would/could be a related mechanism. In Perl 6 you can at least get it down the minimalistic indication of a method vs function: given $h { .body( .head( .title( 'FooPage' ) ), .body( ... ) ); } That can be construed as clean in a way that a functional interface with an implicit object could not. P6 is big on distinguishing method calls from function calls *because* of wanting to distinguish object-centric single dispatch from function-based multiple dispatch (including all operator dispatch) which, by the way, is generally controlled lexically in P6, as the OP suggests. (It's also used in the global (or more like super-lexical) Prelude scope by the compiler to define the base language each compilation unit starts in.) So we're ahead of you there... :) Basically anything that could be construed as language mutation is limited lexically in P6, and mixing in user-defined multimethods can be construed as at least semantic mutation, and is also syntactic mutation if you define new operators rather than merely overloading existing ones. (We have a bias toward new operators for different semantics, also suggested in the OP. There's lots of Unicode operators available, I hear...) But back to .body etc. To go further than that without the cooperation of the class, you'd have to curry the invocant on a class, currently described as something like: (use HTML::Tiny).assuming(:self(HTML::Tiny.new())); which would presumably import all the methods as functions, give or take the fact that that syntax would not intrinsically indicate the desire to import anything, which is a problem. It is probably a common enough operation to give a shortcut to: use HTML::Tiny :singleton; or some such, which would automatically run new, curry all the methods on the invocant, install those resulting functions under the singleton tag as marked for export, then import them as you would any other tag. Then your call reduces to: body( head( title( 'FooPage' ) ), body( ... ) ); But as I just described it, if you wanted to use another singleton in a different scope, you'd end up clobbering singleton tag, so really you want to treat that as an anonymous tag somehow. (Import tags are really just subpackages in P6, so an anonymous temporary subpackage is likely not a problem.) Then you wouldn't have colliding curries, and the exporting module doesn't have to be aware of who is importing from it, which is pretty bogus when you think about it. Presumably the HTML::Tiny protoobject can then be queried for its singleton object if you really need to have $h for some reason. Larry
Re: Musings on operator overloading (was: File-Fu overloading)
At 17:30 + 2/24/08, Luke Palmer wrote: On Sun, Feb 24, 2008 at 3:00 PM, Aristotle Pagaltzis [EMAIL PROTECTED] wrote: And I read both very carefully and failed to understand most of it. I use perl for physics and engineering mostly because I forgot most of my FORTRAN long ago and perl works everywhere. I really want to use complex numbers, vectors, matrices, and sometimes quarternions. I really want to be able to define or use previously defined operators in a way that I learned in the 50's. I want my compiler to understand when I use vectors in which the components are complex numbers. I want dot and cross product to work. I want to be able to multiply a matrix by a vector and get a polite error message if I try that with impossible arguments. What I think I learned from those two messages is that it's damnably difficult for a parser to figure out what I'm doing. Perhaps it just isn't worth while. But. . . I really don't mind informing my compiler in advance about what I want a variable to be treated as. Typedef {}, Dimension () and the like are no problem at all. I don't mind. And I think that would also apply to my scientifically oriented friends. Wouldn't it make life easier for the parser to overload the * operator into a dot product whenever both arguments have been defined as vectors or been returned as vectors by a previous operation? One could even use ** for a cross product since raising to a vector power is unreasonable. Just recognizing the special use declared and passing the operation off to a required subroutine would be adequate. Yes. It can all be expressed in simple object-oriented language but all of the File::Fu stuff is unduly complicating the use in mathematics. Practical Extraction and Reporting are what perl is about and I know I'm stretching the plan but just a bit of code that will allow, but not require, typedefs - er classes - of special things that cause operators to be passed to subroutines - er class methods - to be written could make a big difference. Even translating ^ to pow($x,$y) would be useful to some, but I remember that much FORTRAN. And -2^2 is -4 (correctly?) in C on a two's complement machine. -- -- Life begins at ovulation. Ladies should endeavor to get every young life fertilized. --
Re: Musings on operator overloading (was: File-Fu overloading)
Aristotle Pagaltzis wrote: And this contradiction – that being able to declare sugar is good, but the way that languages have permitted that so far leads to insanity – is what sent me thinking along the lines that there has to be some way to make overloading sane. And we all know that all is fair if you predeclare. And that led me to the flash of inspiration: why not make overloading a property of the source (lexical, early-bound) rather than of the values (temporal, late- bound)? And what we need to do that is a way to say this scope is special in that the operators herein follow rules that differ from the normal semantics. There you have it. So if I'm understanding you correctly, the following would be an example of what you're talking about: { use text; if $a 49 { say $a } } ...with the result being the same as Perl5's 'if $a gt 49 { say $a }' (so if $a equals '5', it says '5'). Am I following you? If so, I'm not seeing what's so exciting about the concept; all it is is a package that redefines a set of operators for whatever scopes use it. If I'm not following you, I'm totally lost. -- Jonathan Dataweaver Lang
Re: Musings on operator overloading (was: File-Fu overloading)
On 2008-Feb-24, at 2:28 pm, Jonathan Lang wrote: { use text; if $a 49 { say $a } } ...with the result being the same as Perl5's 'if $a gt 49 { say $a }' (so if $a equals '5', it says '5'). Am I following you? If so, I'm not seeing what's so exciting about the concept; The whole point is to be not exciting: instead of being kept on the edge of your seat wondering what possible meaning has this time, it's right there explicitly, boringly in front on you. As indicated, that has advantages and disadvantages. In general, I tend towards solutions that do what human beings would do (as opposed to programmers, although of course that isn't always feasible). One thing humans do, when faced with a dot product, say, is to use a dot; and happily, Perl 6 makes it easy to define Unicode operators so we don't have to overload operators that mean something else. Something else humans do, however, is to overload symbols: e.g. / for a filepath separator and for division. I'm not convinced that scope-based overloading is the way to go in this particular case, though. It is the way to go for regexes, which overload all sorts of symbols that have other meanings, because regexes come in self- contained lumps anyway. (Although similar overloadings are used in Signatures, which are another limited scope, come to think of it). Of course, using a slash for division is a slightly ugly hack anyway, because typewriters didn't have the proper symbol (U+00F7). P6 could use ÷ for division, and / for portable path-separation. (Which is kind of tempting, at least to me; I must admit I've been pondering the use of / for filenames for some time.) On the other hand, I think that in real code, it should be fairly obvious whether you're doing arithmetic or working with files, so perhaps the solution is to add unambiguous alternatives for those exceptional cases when you want to make it absolutely explicit: open($dir fs ($filename ~ $total div $count)). (I also expect that files will be treated more consistently in P6, without as many issues about whether a file is a string or a handle or an object...) -David
Re: overloading the variable declaration process
On 2/12/06, Thomas Sandlass [EMAIL PROTECTED] wrote: IIRC, you can always create a new method for a class, even outside of its definition, simply by ensuring that the first parameter to be passed in will be an object of that type: method bark (Dog $_) { ... } I don't think this is true unless it is a multi method, in which case it is not actually a method of the of the class, but instead just DWIMs because of MMD and the fact we allow an invocant calling style freely. Yes, the question of ownership of methods is still somewhat unresolved. I think we need to distinguish something I've called slots in an object from free (multi) methods that are defined outside of the class definition block. BTW, do the outsiders have access to the private data slots with the $! twigil? I think that multimethods defined outside of the scope of the class should not have access to the classes data slots, it should use the accessors. And those multimethods should live in the package in which they are defined. The class implementation can stash refs to multimethods which apply to it for optimization reasons, but this has nothing to do with the language design itself. As far as method name disambiguation, we should use the calling style (invocant vs. normal function call) to determine which method to call. I am sure there are other edge cases to be uncovered here as well, but I can't think of them at the moment. Stevan
RE: overloading the variable declaration process
Stevan Little wrote: ^Dog is an instance of the MetaClass, while Dog (no ^ sigil) is the class (actually it's a prototypical instance of the class which the metaclass ^Dog describes, but you dont really need to know that to use it). ^Dog.can(bark) # false Dog.can(bark) # true Wasn't the ^ sigil dropped in favor of a 0..^n list creation op? So the first line is spelled ::Dog.can(bark) # false instead? Of course you have a conceptual circulatiry issue now because well,.. what is a MetaClass? Well it could be an instance of a MetaMetaClass, but what is that an instance of? This could go on forever (turtles all the way down as it is sometimes called). But in practice you either just stop and say this is as far as it goes, or you bootstrap your class model somehow and tie the knot. I prefer the boostrapping as it is much more elegant and tends to allow for much more flexibility. I agree. Your cicularity is basically an a-priori infinity conceptually one level outside of the meta system. And there will be an orthogonal type/kind system. IIRC, you can always create a new method for a class, even outside of its definition, simply by ensuring that the first parameter to be passed in will be an object of that type: method bark (Dog $_) { ... } I don't think this is true unless it is a multi method, in which case it is not actually a method of the of the class, but instead just DWIMs because of MMD and the fact we allow an invocant calling style freely. Yes, the question of ownership of methods is still somewhat unresolved. I think we need to distinguish something I've called slots in an object from free (multi) methods that are defined outside of the class definition block. BTW, do the outsiders have access to the private data slots with the $! twigil? or maybe method Dog.bark () { ... } Yes that works too. Shouldn't that read Dog::bark? Why the dot? -- $TSa.greeting := HaloO; # mind the echo!
Re: overloading the variable declaration process
Thomas Sandlass wrote: or maybe method Dog.bark () { ... } Yes that works too. Shouldn't that read Dog::bark? Why the dot? Because I'm not 100% with the proper syntax of things. The intent was to add a bark() method to Dog during runtime. -- Jonathan Dataweaver Lang
Re: overloading the variable declaration process
On 2/8/06, Jonathan Lang [EMAIL PROTECTED] wrote: Stevan Little wrote: Yes, that is correct, because: Dog.isa(Dog) # true $spot.isa(Dog) # true ^Dog.isa(Dog) # false In fact ^Dog isa MetaClass (or Class whatever you want to call it). At least that is how I see/understand it. OK. To help me get a better idea about what's going on here, what sorts of attributes and methods would ^Dog have? Well, a metaclass describes the behaviors and attributes of a class, and ^Dog is an *instance* of the metaclass. So actually ^Dog would not actually have attributes and methods since it is an instance. That said, I think ^Dog would probably respond to methods like these (some of which are described in S12): ^Dog.name # Dog ^Dog.version # 0.0.1 (or something similiar of course) ^Dog.authority # cpan:LWALL or email:[EMAIL PROTECTED] ^Dog.identifier # returns the string Dog-0.0.1-cpan:LWALL I would like to see some methods like this: # dynamically add a method that # Dog and $spot would respond to ^Dog.add_method(bark = method () { ... }); Which would be like doing this in Perl 5: no strict 'refs'; *{'Dog::bark'} = sub { ... }; And of course if you can add a method, you will need to be able to fetch and delete them as well, so a get_method and remove_method would be in order as well. And if you can add methods, surely you can add attributes, so (add|get|remove)_attribute would be needed. ^Dog.add_attribute(:label$fur, :accessrw); Would be equivalent to saying this: class Dog is reopened { has $fur is rw; } And ^Dog would also provide access to infromation about super and subclasses as well. So superclasses and subclasses methods would make sense too. We would also need methods to deal with Role relationships as well. So, given the above items, the class MetaClass might look something like this: class MetaClass { has $name is rw; has $version is rw; has $authority is rw; has @superclasses; has @subclasses; has %methods; has %attributes; method identifier { ... } method superclasses { ... } method subclasses { ... } method add_method { ... } method get_method { ... } method remove_method { ... } method add_attribute { ... } method get_attribute { ... } method remove_attribute { ... } } So given this, you could almost look at this code: class Foo-0.0.1-cpan:JRANDOM { has $bar is rw; method baz (Foo $self:) { ... } } As being roughly equivalent to the following code: ^Foo := MetaClass.new(); ^Foo.name('Foo'); ^Foo.version(0.0.1); ^Foo.authority(:cpanJRANDOM); ^Foo.add_attribute(:label$bar, :accessrw); ^Foo.add_method(baz = method (Foo $self) { ... }); Of course this is mostly unspecced, and it is still unclear exactly how much of this meta-level API will be accessible in Perl 6 itself. And as far the the Pugs work on this goes, we plan to have something similar to the above available in the next release (6.28.0). Hope this helps. Stevan
Re: overloading the variable declaration process
Stevan Little wrote: Jonathan Lang wrote: OK. To help me get a better idea about what's going on here, what sorts of attributes and methods would ^Dog have? Well, a metaclass describes the behaviors and attributes of a class, and ^Dog is an *instance* of the metaclass. So actually ^Dog would not actually have attributes and methods since it is an instance. Huh? A dog can bark; so the Dog class should have a method called 'bark'. Or does 'can' not mean what it seems to mean? That said, I think ^Dog would probably respond to methods like these (some of which are described in S12): OK; apparently, what I meant when I asked what methods and attributes does ^Dog have? is what you're talking about when you speak of which methods ^Dog will respond to. To me, an object has whatever methods that it responds to. ^Dog.name # Dog ^Dog.version # 0.0.1 (or something similiar of course) ^Dog.authority # cpan:LWALL or email:[EMAIL PROTECTED] ^Dog.identifier # returns the string Dog-0.0.1-cpan:LWALL Would it be valid to speak of ^$spot? If so, what would ^$spot.name be? I would like to see some methods like this: # dynamically add a method that # Dog and $spot would respond to ^Dog.add_method(bark = method () { ... }); Which would be like doing this in Perl 5: no strict 'refs'; *{'Dog::bark'} = sub { ... }; IIRC, you can always create a new method for a class, even outside of its definition, simply by ensuring that the first parameter to be passed in will be an object of that type: method bark (Dog $_) { ... } or maybe method Dog.bark () { ... } And of course if you can add a method, you will need to be able to fetch and delete them as well, so a get_method and remove_method would be in order as well. To fetch a method, why not have .can() return a reference to the method upon success? I might even go so far as to treat can() as an lvalue, using the assignment of a coderef as an alternate way of adding or changing the object's behavior on the fly: method bark (Dog $_:) { ... }; Dog.can(bark) = method () { ... }; # Teach the dog a new trick Dog.can(bark) = true; # inform the dog that it ought to know how to bark, without telling it how, yet; equivalent to a literal = method { ... }. Dog.can(bark) = false; # tell the dog to forget how to bark. Dog.can(bark) = undef; # Ditto. (Doing this to Dog DWIMs to modifying the behavior of all dogs at once - you're declaring that dogs can bark or this is how dogs bark, whereas doing it to $spot DWIMs to modifying the behavior of $spot only: $brutus.can('bark') = false: my best friend's pet dog seems to have lost the capacity to bark in its old age; that doesn't mean that dogs in general can't bark.) Similar things might be done with .has (for attributes), .isa (for superclasses), and .does (for roles). -- Jonathan Dataweaver Lang
Re: overloading the variable declaration process
On 2/9/06, Jonathan Lang [EMAIL PROTECTED] wrote: Stevan Little wrote: Jonathan Lang wrote: OK. To help me get a better idea about what's going on here, what sorts of attributes and methods would ^Dog have? Well, a metaclass describes the behaviors and attributes of a class, and ^Dog is an *instance* of the metaclass. So actually ^Dog would not actually have attributes and methods since it is an instance. Huh? A dog can bark; so the Dog class should have a method called 'bark'. Or does 'can' not mean what it seems to mean? ^Dog is an instance of the MetaClass, while Dog (no ^ sigil) is the class (actually it's a prototypical instance of the class which the metaclass ^Dog describes, but you dont really need to know that to use it). ^Dog.can(bark) # false Dog.can(bark) # true This is a very important distinction. Saying Dog class has a method called 'bark', implies the following statements are true - Dog will respond to the method called bark. - Given my Dog $spot, $spot will respond to the method called bark. - ^Dog (the metaclass instance which describes a class called Dog) does *not* respond to the method called bark. - ^Dog (since it describes the class called Dog) manages all of the methods which Dog and $spot will respond too, one of which is called bark. There is a clear line between the meta-level (where ^Dog lives) and the user-level (where Dog and $spot) live. This is a line which is heavily blurred in Perl 5, and in many OO languages (aside from Smalltalk, CLOS and a few others) the meta-level is just not accessible at all from user-land. That said, I think ^Dog would probably respond to methods like these (some of which are described in S12): OK; apparently, what I meant when I asked what methods and attributes does ^Dog have? is what you're talking about when you speak of which methods ^Dog will respond to. To me, an object has whatever methods that it responds to. I disagree, an object is an instance of a class. A class has the methods that the object will respond too. You would not want to store all the methods in each instance, it would not make sense. Each instance needs to share a set of methods, and those methods are stored in the class. Well what is a class? In Perl 5 a class is simply a package, and the subs in that package are methods. In Perl 6 however, a class will be an instance of another class, the MetaClass. These two things are really not that different when you think about it. - A Perl 5 package holds methods for you by storing them in the symbol table. You can add, get, remove these methods from the symbol table using the symbol table API. - A Perl 6 class holds methods for you by storing them inside an instance variable in an instance of the MetaClass, and you can add, get, remove these methods by using the methods of MetaClass. Of course you have a conceptual circulatiry issue now because well,.. what is a MetaClass? Well it could be an instance of a MetaMetaClass, but what is that an instance of? This could go on forever (turtles all the way down as it is sometimes called). But in practice you either just stop and say this is as far as it goes, or you bootstrap your class model somehow and tie the knot. I prefer the boostrapping as it is much more elegant and tends to allow for much more flexibility. ^Dog.name # Dog ^Dog.version # 0.0.1 (or something similiar of course) ^Dog.authority # cpan:LWALL or email:[EMAIL PROTECTED] ^Dog.identifier # returns the string Dog-0.0.1-cpan:LWALL Would it be valid to speak of ^$spot? If so, what would ^$spot.name be? There is no such thing as a ^$spot. The ^ is the class sigil, and will hold metaclass instances only, just as variables with % will only holds hashes, and variables with @ will only holds arrays, etc. I would like to see some methods like this: # dynamically add a method that # Dog and $spot would respond to ^Dog.add_method(bark = method () { ... }); Which would be like doing this in Perl 5: no strict 'refs'; *{'Dog::bark'} = sub { ... }; IIRC, you can always create a new method for a class, even outside of its definition, simply by ensuring that the first parameter to be passed in will be an object of that type: method bark (Dog $_) { ... } I don't think this is true unless it is a multi method, in which case it is not actually a method of the of the class, but instead just DWIMs because of MMD and the fact we allow an invocant calling style freely. or maybe method Dog.bark () { ... } Yes that works too. But TIMTOWTDI, and each has it's own benefits. Your above approach works fine while you are writing the code, but is not as useful for dynamically adding a method at runtime (unless you use eval(), but that gets ugly). Using the metaclass API dynamically adding a method to a class at runtime is trivial, again, think of it as being no different that doing this in Perl 5: # deep within a function
Re: overloading the variable declaration process
Stevan Little wrote: Jonathan Lang wrote: OK; apparently, what I meant when I asked what methods and attributes does ^Dog have? is what you're talking about when you speak of which methods ^Dog will respond to. To me, an object has whatever methods that it responds to. I disagree, an object is an instance of a class. A class has the methods that the object will respond too. You would not want to store all the methods in each instance, it would not make sense. Each instance needs to share a set of methods, and those methods are stored in the class. I think that we're talking past each other: you're trying to educate me on how a programmer should think about objects and classes; I'm trying to figure out how a non-programmer thinks of them. To non-programmers (and amateur programmers), objects aren't instances of classes; classes are categories of related objects. Objects have behaviors and characteristics; classes are a convenient shorthand for describing behaviors and characteristics common to a set. Objects come first, while classes are thought of in the context of objects. The same implementation can be used for both perspectives: dogs can bark; Spot is a dog; therefore, Spot can bark is a form of reasoning that underlies using the class-and-instance model for the back-end implementation of the object-and-category paradigm. classes have methods; objects respond to them is part of the classes-and-instances paradigm; but that isn't really how people think. In terms of practical differences: under the classes-and-instances paradigm, if you want to create an object whose behavior differs slightly from a given class, you need to create a subclass that has the desired behavior and to create the object as an instance of that subclass. With the object-and-category paradigm, there's nothing that insists that every object's behavior must conform precisely to the behaviors described by its classes; the latter are merely rules of thumb to apply to the former until you learn differently, and behaviors can be added, removed, or tweaked on an individual basis. This is why (last I checked) but creates a behind-the-scenes 'singleton' subclass for the new object instead of demanding that a new subclass be explicitly created, and why I suggested the possibility of adding, replacing, or removing methods for individual objects as well as for classes (which, presumably, would also be implemented under the hood by replacing the object's class by a 'singleton' subclass). ^Dog.name # Dog ^Dog.version # 0.0.1 (or something similiar of course) ^Dog.authority # cpan:LWALL or email:[EMAIL PROTECTED] ^Dog.identifier # returns the string Dog-0.0.1-cpan:LWALL Would it be valid to speak of ^$spot? If so, what would ^$spot.name be? There is no such thing as a ^$spot. OK. The only reason I was thinking in those terms was because of the possibility that $spot might be based on one of those behind-the-scenes customized subclasses that I mentioned earlier: if my Dog $brutus but cannot(bark); How do you access the subclass of Dog that $brutus is the instance of? IIRC, you can always create a new method for a class, even outside of its definition, simply by ensuring that the first parameter to be passed in will be an object of that type: method bark (Dog $_) { ... } I don't think this is true unless it is a multi method, in which case it is not actually a method of the of the class, but instead just DWIMs because of MMD and the fact we allow an invocant calling style freely. I was under the impression that the distinction between a method and a multi-method was how many of the parameters get used to dispatch: methods aren't really owned by classes, any more than class definition is a declarative process; it just looks that way on the surface. Am I wrong about this? or maybe method Dog.bark () { ... } Yes that works too. But TIMTOWTDI, and each has it's own benefits. I'm aware of that, and was proposing this as Another Way. Your above approach works fine while you are writing the code, but is not as useful for dynamically adding a method at runtime (unless you use eval(), but that gets ugly). I was under the impression that class definition was fundamentally a functional process dressed up as a declarative process. method Dog.bark () { ... } would seem to me to be a means of continuing that process after the fact - that is, adding a method to a class after you've left the class definition block. It seems to serve exactly the same purpose as using the metaclass API. That is, I see it as being alternate syntax for ^Dog.add_method(bark = method () { ... }). To fetch a method, why not have .can() return a reference to the method upon success? I might even go so far as to treat can() as an lvalue, using the assignment of a coderef as an alternate way of adding or changing the object's behavior on the fly: method bark (Dog $_:) { ...
Re: overloading the variable declaration process
Stevan~ On 2/7/06, Stevan Little [EMAIL PROTECTED] wrote: After all Foo is just a specific instance of the class Class. Shhh... class objects don't exist ... I was never here,... I will I count to three and when I snap my fingers you will awaken and will have forgotten all about class Class. 1 ... 2 ... 3 ... *snap* ... What!?!? Where was I? Oh, yeah. As I was saying, I think we just take C++'s object system exactly. Matt -- Computer Science is merely the post-Turing Decline of Formal Systems Theory. -Stan Kelly-Bootle, The Devil's DP Dictionary
Re: overloading the variable declaration process
On Tue, Feb 07, 2006 at 07:32:18PM -0500, Stevan Little wrote: : On 2/7/06, Matt Fowles [EMAIL PROTECTED] wrote: : Stevan~ : : I am going to assume that you intended to reply to perl 6 language, : and thus will include your post in its entirety in my response. : : Yes, sorry... I missed the reply to all button on the gmail UI by a : few pixels I guess. Thank you for forwarding. : : Now that everyone is on the same page, I will go about responding : : : # snip some code : : : class Pipe::Stem { : has $composed_of; : has $color; : has $length; : has $filter = bool::false; : } : : so far I am mostly with you, except one question. Does has $filter = : bool::false; just provide a default? : : Yes, that is a default value. I assume that most Pipe smokers don't : like filters in their pipes, I might be wrong on that one because I am : not a pipe smoker :) : : You would then model the different pipes you sell; : : class MagrittePipe { : has $stem = Pipe::Stem.new( ::composed_ofebony, ::colorblack, ::lengthshort :); : has $bowl = Pipe::Bowl.new( ::composed_ofmahogany, ::colorbrown, ::sizemedium :); : } : : Now, you might say, why not make the MagrittePipe an instance of Pipe, : and give the Pipe class a few more attributes, like a name. Well, if : you did that then you couldn't subclass it of course. : : Actually, I was going to ask why not make MagrittePipe inherit from Pipe. : : Ooops, forgot that part it should infact inherit from Pipe. And of : course you can do that dynamically with the metamodel ;) : : Well, using introspection, it becomes very simple to discover various : qualities about your inventory, enough to probably even autogenerate : the HTML pages for your online-web store (powered by Perl 6 of : course). And lets not forget the uber-cool Perl 6 Object Database : which you are using to store your real-time inventory in (all : metamodel powered of course). And of course if you want, you can use : the DistributedObjectProxy metaclass which will automatically make : your objects distributed so that your door-to-door Pipe saleforce can : update your inventory in real time from their cellphones. And your RD : department can use the built-in (but as yet unspeced) logic : programming features of Perl 6 to mine your customer information from : your (previously mentioend) object database and genetically grow : new, more desireable Pipe products (which is easy to do since your : metaclasses are programatically composable (and no I don't mean eval : $code)). : : I think you mis-understand me. I do not question the value of a : powerful meta-model. Quite the contrary I want to see Perl 6 have a : meta-model more powerful and accessible then CLOS. I see it as a : necessity for a language that plans to truely scale in the future. : : What I do question is the usefullness of having bare class names : represent these prototype objects. I just don't really understand : what they are for or do. : : Well, to be totally honest, I think only Larry truely understands : their usage, but to the best of my understanding they are intented to : serve a number of roles; : : (Larry, please correct me if I am wrong here) : : - to allow for introspection of the class. : : After all ^Foo.can() is really just a series of method calls to the : Foo metaobject. And besides ^Foo.meta.can() is 5 more characters to : type!! : : - provide an invocant for class methods. : : Larry does not like the class-method/instance-method distinction (in : fact it seems he doesn't even like the class/instance distinction : either), and has declared that a class method is really just a : method of the class which does not access any instance attributes. : Well, this complicates the type signature of the invocant, and we need : an invocant that the type-checker can check. : : In Perl 5, classes were just package names which were just strings. : This will not work in Perl 6 in the presence of a reasonably decent : type checker, the class needs to be *something*. Now Larry has also : declared that he does not like the idea of a class object, I think : this is because that means that a properly typed method signature for : a class method would look like this: : : class Foo { : method foo (Class $class:) { : say I am a class method, and proud of it; : } : } : : According to the signature, this method takes any Class instance as an : invocant. Well : thats just not right because it should only accept the Class instance : which represents the Foo class. But we can't (at least I dont think we : can) be that specific, at least not easily enough to also allow this : method
Re: overloading the variable declaration process
Consider my Dog $spot. From the Perl6-to-English Dictionary: Dog: a dog. $spot: the dog that is named Spot. ^Dog: the concept of a dog. Am I understanding things correctly? If so, here's what I'd expect: a dog can bark, or Spot can bark; but the concept of a dog cannot bark: can Dog bark; # answer: yes can $spot bark; # answer: yes can ^Dog bark; # answer: no -- Jonathan Dataweaver Lang
Re: overloading the variable declaration process
On 2/8/06, Jonathan Lang [EMAIL PROTECTED] wrote: Consider my Dog $spot. From the Perl6-to-English Dictionary: Dog: a dog. $spot: the dog that is named Spot. ^Dog: the concept of a dog. Am I understanding things correctly? If so, here's what I'd expect: a dog can bark, or Spot can bark; but the concept of a dog cannot bark: can Dog bark; # answer: yes can $spot bark; # answer: yes can ^Dog bark; # answer: no Yes, that is correct, because: Dog.isa(Dog) # true $spot.isa(Dog) # true ^Dog.isa(Dog) # false In fact ^Dog isa MetaClass (or Class whatever you want to call it). At least that is how I see/understand it. Stevan
Re: overloading the variable declaration process
Stevan Little wrote: Yes, that is correct, because: Dog.isa(Dog) # true $spot.isa(Dog) # true ^Dog.isa(Dog) # false In fact ^Dog isa MetaClass (or Class whatever you want to call it). At least that is how I see/understand it. OK. To help me get a better idea about what's going on here, what sorts of attributes and methods would ^Dog have? -- Jonathan Dataweaver Lang
Re: overloading the variable declaration process
On 2/6/06, Larry Wall [EMAIL PROTECTED] wrote: So the basic answer to you question is, I think, yes. If Dog chooses to always return true for .defined, then (in Haskell terms) it's more like a Just type than a Maybe type. Perl 6's objects like to be Maybe types by default, but you can override it. (I'm using the Haskell terms loosely here, of course.) But the very concept of definedness is getting mushy in Perl 6. What we need is more concepts of the form Is this *sufficiently* defined for what I want to do with it? That's why I proposed defined according to a particular role as one way to ask that sort of question. So, if ^Dog describes a Dog which defines a $dog, do we need an undescribed() function? Just kidding... kinda. Ashley Winters
Re: overloading the variable declaration process
On Mon, Feb 06, 2006 at 10:41:02PM -0500, Matt Fowles wrote: : Larry~ : : On 2/6/06, Larry Wall [EMAIL PROTECTED] wrote: : This is mostly motivated by linguistics rather than computer science, : insofar as types/classes/roles in natural language are normally : represented by generic objects rather than meta objects. When I : ask in English: : : Can a dog bark? : : that's equivalent to asking in Perl 6: : : Dog.can('bark') : : Or you might think of it more as a question like Can the ideal of a : dog bark? the answer to which is of course No, it doesn't exist.. As soon as you say the ideal you've chosen Platonism over Aristotelianism. :-) : Perhaps, I am just too firmly rooted in old paradigms but I think it : is very important not to conflate the representation of a thing with : the thing. : : http://en.wikipedia.org/wiki/Image:MagrittePipe.jpg Indeed, and the modeling point of view is that $pipe is *also* just a representation of the Pipe. Neither Pipe nor $pipe is the thing itself. Most computer programs are about Something Else, so computer languages should be optimized for talking about other things rather than talking about themselves. The answer to Pipe.can(Smoke) $pipe.can(Smoke) should be the same, not different. On the other hand, ^Pipe.can(Smoke) is a different matter, insofar as you're asking a question about a Class object rather than a Pipe object. And now you get your Platonism back. You just have to be explicit about it. Larry
Re: overloading the variable declaration process
Larry~ On 2/7/06, Larry Wall [EMAIL PROTECTED] wrote: Indeed, and the modeling point of view is that $pipe is *also* just a representation of the Pipe. Neither Pipe nor $pipe is the thing itself. Most computer programs are about Something Else, so computer languages should be optimized for talking about other things rather than talking about themselves. The answer to Pipe.can(Smoke) $pipe.can(Smoke) should be the same, not different. On the other hand, ^Pipe.can(Smoke) is a different matter, insofar as you're asking a question about a Class object rather than a Pipe object. And now you get your Platonism back. You just have to be explicit about it. I see the value of ^Pipe and $pipe as seperate objects which can be manipulated programmatically. What I don't really understand is what exactly Pipe is and where it would be useful. They way you have described Pipe feels a little muddy to me and I am unsure about its purpose and semantics. Is it just an object I ask `.can()` or does it have some deeper usefulness? Matt -- Computer Science is merely the post-Turing Decline of Formal Systems Theory. -Stan Kelly-Bootle, The Devil's DP Dictionary
Re: overloading the variable declaration process
Stevan~ I am going to assume that you intended to reply to perl 6 language, and thus will include your post in its entirety in my response. On 2/7/06, Stevan Little [EMAIL PROTECTED] wrote: On 2/7/06, Matt Fowles [EMAIL PROTECTED] wrote: Larry~ On 2/7/06, Larry Wall [EMAIL PROTECTED] wrote: Indeed, and the modeling point of view is that $pipe is *also* just a representation of the Pipe. Neither Pipe nor $pipe is the thing itself. Most computer programs are about Something Else, so computer languages should be optimized for talking about other things rather than talking about themselves. The answer to Pipe.can(Smoke) $pipe.can(Smoke) should be the same, not different. On the other hand, ^Pipe.can(Smoke) is a different matter, insofar as you're asking a question about a Class object rather than a Pipe object. And now you get your Platonism back. You just have to be explicit about it. I see the value of ^Pipe and $pipe as seperate objects which can be manipulated programmatically. What I don't really understand is what exactly Pipe is and where it would be useful. They way you have described Pipe feels a little muddy to me and I am unsure about its purpose and semantics. Is it just an object I ask `.can()` or does it have some deeper usefulness? Well since ^Pipe will really just be the same value as Pipe.meta, then you can do many things with it (if I get my metamodel wishes that is). Now, in keeping with the examples of useful things for people other than programmers and computers spirit of this discussion, here is one possible approach to using metaclasses in a constructive way. Okay, so lets assume you own a tobacco shop, and you have modeled a Pipe hierarchy to represent all the pipes you sell. Your base classes might look something like this: class Pipe { has $stem; has $bowl; } class Pipe::Bowl { has $composed_of; has $color; has $size; } class Pipe::Stem { has $composed_of; has $color; has $length; has $filter = bool::false; } You would then model the different pipes you sell; class MagrittePipe { has $stem = Pipe::Stem.new( :composed_ofebony, :colorblack, :lengthshort ); has $bowl = Pipe::Bowl.new( :composed_ofmahogany, :colorbrown, :sizemedium ); } Now, you might say, why not make the MagrittePipe an instance of Pipe, and give the Pipe class a few more attributes, like a name. Well, if you did that then you couldn't subclass it of course. class MagrittePipe::SpecialEngravedAnniversayEdition { is MagrittePipe; does Engraved[$engraving_text = Ceci n'est pas une pipe]; does SpecialEdition[$typeAnniversay]; } Now, what does all this have to do with metamodel? Well, using introspection, it becomes very simple to discover various qualities about your inventory, enough to probably even autogenerate the HTML pages for your online-web store (powered by Perl 6 of course). And lets not forget the uber-cool Perl 6 Object Database which you are using to store your real-time inventory in (all metamodel powered of course). And of course if you want, you can use the DistributedObjectProxy metaclass which will automatically make your objects distributed so that your door-to-door Pipe saleforce can update your inventory in real time from their cellphones. And your RD department can use the built-in (but as yet unspeced) logic programming features of Perl 6 to mine your customer information from your (previously mentioend) object database and genetically grow new, more desireable Pipe products (which is easy to do since your metaclasses are programatically composable (and no I don't mean eval $code)). Of course, I am just dreaming here, but maybe I am not! Most of this is already possible using CLOS (see the Franz's AllegroCL 8.0 it's bad*ss IMO), so why can't we have it? Anyway, I hope that doesn't make your head hurt too much Matt ;) Now that everyone is on the same page, I will go about responding class Pipe { has $stem; has $bowl; } class Pipe::Bowl { has $composed_of; has $color; has $size; } class Pipe::Stem { has $composed_of; has $color; has $length; has $filter = bool::false; } so far I am mostly with you, except one question. Does has $filter = bool::false; just provide a default? You would then model the different pipes you sell; class MagrittePipe { has $stem = Pipe::Stem.new( :composed_ofebony, :colorblack, :lengthshort ); has $bowl = Pipe::Bowl.new(
Re: overloading the variable declaration process
On 2/7/06, Matt Fowles [EMAIL PROTECTED] wrote: Stevan~ I am going to assume that you intended to reply to perl 6 language, and thus will include your post in its entirety in my response. Yes, sorry... I missed the reply to all button on the gmail UI by a few pixels I guess. Thank you for forwarding. Now that everyone is on the same page, I will go about responding # snip some code class Pipe::Stem { has $composed_of; has $color; has $length; has $filter = bool::false; } so far I am mostly with you, except one question. Does has $filter = bool::false; just provide a default? Yes, that is a default value. I assume that most Pipe smokers don't like filters in their pipes, I might be wrong on that one because I am not a pipe smoker :) You would then model the different pipes you sell; class MagrittePipe { has $stem = Pipe::Stem.new( :composed_ofebony, :colorblack, :lengthshort ); has $bowl = Pipe::Bowl.new( :composed_ofmahogany, :colorbrown, :sizemedium ); } Now, you might say, why not make the MagrittePipe an instance of Pipe, and give the Pipe class a few more attributes, like a name. Well, if you did that then you couldn't subclass it of course. Actually, I was going to ask why not make MagrittePipe inherit from Pipe. Ooops, forgot that part it should infact inherit from Pipe. And of course you can do that dynamically with the metamodel ;) Well, using introspection, it becomes very simple to discover various qualities about your inventory, enough to probably even autogenerate the HTML pages for your online-web store (powered by Perl 6 of course). And lets not forget the uber-cool Perl 6 Object Database which you are using to store your real-time inventory in (all metamodel powered of course). And of course if you want, you can use the DistributedObjectProxy metaclass which will automatically make your objects distributed so that your door-to-door Pipe saleforce can update your inventory in real time from their cellphones. And your RD department can use the built-in (but as yet unspeced) logic programming features of Perl 6 to mine your customer information from your (previously mentioend) object database and genetically grow new, more desireable Pipe products (which is easy to do since your metaclasses are programatically composable (and no I don't mean eval $code)). I think you mis-understand me. I do not question the value of a powerful meta-model. Quite the contrary I want to see Perl 6 have a meta-model more powerful and accessible then CLOS. I see it as a necessity for a language that plans to truely scale in the future. What I do question is the usefullness of having bare class names represent these prototype objects. I just don't really understand what they are for or do. Well, to be totally honest, I think only Larry truely understands their usage, but to the best of my understanding they are intented to serve a number of roles; (Larry, please correct me if I am wrong here) - to allow for introspection of the class. After all ^Foo.can() is really just a series of method calls to the Foo metaobject. And besides ^Foo.meta.can() is 5 more characters to type!! - provide an invocant for class methods. Larry does not like the class-method/instance-method distinction (in fact it seems he doesn't even like the class/instance distinction either), and has declared that a class method is really just a method of the class which does not access any instance attributes. Well, this complicates the type signature of the invocant, and we need an invocant that the type-checker can check. In Perl 5, classes were just package names which were just strings. This will not work in Perl 6 in the presence of a reasonably decent type checker, the class needs to be *something*. Now Larry has also declared that he does not like the idea of a class object, I think this is because that means that a properly typed method signature for a class method would look like this: class Foo { method foo (Class $class:) { say I am a class method, and proud of it; } } According to the signature, this method takes any Class instance as an invocant. Well thats just not right because it should only accept the Class instance which represents the Foo class. But we can't (at least I dont think we can) be that specific, at least not easily enough to also allow this method to be called by an instance of Foo as well. So, the solution, use prototype instances for class objects. So now we can properly type our class method for both Foo and $foo like this: class Foo { method foo (Foo $class:) { say I am a class method, and proud of it; } } And whalla,
Re: overloading the variable declaration process
Stevan~ On 2/7/06, Stevan Little [EMAIL PROTECTED] wrote: Well, to be totally honest, I think only Larry truely understands their usage, but to the best of my understanding they are intented to serve a number of roles; I agree with you about that, which is part of what bothers me. (Larry, please correct me if I am wrong here) - to allow for introspection of the class. After all ^Foo.can() is really just a series of method calls to the Foo metaobject. And besides ^Foo.meta.can() is 5 more characters to type!! - provide an invocant for class methods. Larry does not like the class-method/instance-method distinction (in fact it seems he doesn't even like the class/instance distinction either), and has declared that a class method is really just a method of the class which does not access any instance attributes. Well, this complicates the type signature of the invocant, and we need an invocant that the type-checker can check. In Perl 5, classes were just package names which were just strings. This will not work in Perl 6 in the presence of a reasonably decent type checker, the class needs to be *something*. Now Larry has also declared that he does not like the idea of a class object, I think this is because that means that a properly typed method signature for a class method would look like this: class Foo { method foo (Class $class:) { say I am a class method, and proud of it; } } According to the signature, this method takes any Class instance as an invocant. Well thats just not right because it should only accept the Class instance which represents the Foo class. But we can't (at least I dont think we can) be that specific, at least not easily enough to also allow this method to be called by an instance of Foo as well. So, the solution, use prototype instances for class objects. So now we can properly type our class method for both Foo and $foo like this: class Foo { method foo (Foo $class:) { say I am a class method, and proud of it; } } And whalla, we have a class/instance method ala Perl 5 and it is properly type checkable too. Of course I might be totally wrong here, but this is my best grasp on the subject. Perl 6 allows dispatch on value (if I am not mistaken). Thus, just as we have a sub fact( Int 0 ) { return 0; } sub fact( Int $n ) { return $n * fact($n-1); } Why not have class methods take the form class Foo { method foo (Class Foo) { say I am a class method, and proud of it; } } They are still well types (I think), and properly restricts the types allowed for foo. After all Foo is just a specific instance of the class Class. Matt -- Computer Science is merely the post-Turing Decline of Formal Systems Theory. -Stan Kelly-Bootle, The Devil's DP Dictionary
Re: overloading the variable declaration process
On Sun, Feb 05, 2006 at 07:26:09PM -0800, Darren Duncan wrote: : Part way through writing this, I had a brief chat on #perl6 with : stevan (and apparently the meta-model is still quite in flux) and he : said my question was related to Larry's class but undef idea, and : that Larry should talk more about the subject. Aside from the fact that it's not a class, and not necessarily undef, class but undef is a good name for it. :-) I've been calling them prototype objects lately for lack of a better word. To me, the Real Class is the object instance hiding behind .meta. But when you say bare Foo you actually naming a generic object of the type ^Foo, which I see currently as shorthand for Foo.meta, and which any object that does Foo can get at if it needs metadata, including the Foo object itself. In short, Foo.does('Foo') This is mostly motivated by linguistics rather than computer science, insofar as types/classes/roles in natural language are normally represented by generic objects rather than meta objects. When I ask in English: Can a dog bark? that's equivalent to asking in Perl 6: Dog.can('bark') The Dog there is in the same type category as $dog, and specifically is *not* in the same type category as the class that is managing the logic behind the scenes. As a user, I'm thinking about doggy objects, not classy objects. It's the very same kind of linguistic reasoning that gives us given rather than switch, and when rather than case. People want to think about their problem's objects, not the language implementor's representations of those objects. Now in the case of .can, we do eventually end up asking the metaobject whether this objects supports the .bark method, but the point is that the user doesn't have to keep track of how many metas there are. Or looking at it the other way, any object can stand in for all its meta objects. This is how we think (I think). Psycholinguistially, every dog object in your brain is really a kind of partially instantiated object that is slowly being filled in with knowledge about the real world counterpart to your mental model. Your mental model is never perfect. The trend in the world today is away from monolithic computers that either know everything or nothing, and toward programs that have to work with imperfect knowledge that is generated or downloaded on the fly. So I think the modeling view of reality is the sweet spot for the future, and languages that have to know everything before they think they know anything are doomed to fail. Well, not fail, but have restricted ecological niches, such as rocket science. (And maybe not even there, as machines get more autonomous.) So the basic answer to you question is, I think, yes. If Dog chooses to always return true for .defined, then (in Haskell terms) it's more like a Just type than a Maybe type. Perl 6's objects like to be Maybe types by default, but you can override it. (I'm using the Haskell terms loosely here, of course.) But the very concept of definedness is getting mushy in Perl 6. What we need is more concepts of the form Is this *sufficiently* defined for what I want to do with it? That's why I proposed defined according to a particular role as one way to ask that sort of question. Hope this helps. Larry
Re: overloading the variable declaration process
At 3:02 PM +0800 2/6/06, Audrey Tang wrote: On 2/6/06, Darren Duncan [EMAIL PROTECTED] wrote: Speaking briefly, I would like it if Perl 6 provided a way for a class (or role, or meta-class, etc) to declare that all variables declared to be of that type are automatically/implicitly set to a particular value at declaration time, so that they are not undefined if the programmer using them doesn't explicitly set a value. If so, your use case can be satisfied by declaring that ::NumType (the class object) numifies to 0, and ::StrType stringifies to , via the coerceas form. That could be fine for some situations, but I was looking for a more generic solution for: my FooType $foo; # acts like we said .= new() $foo.do_action(); Essentially, that $foo is like or is a fully instantiated object on which you can call arbitrary FooType object methods as if someone set it with new(), but where in fact the user never did this. The coercing solution won't work if the types of use are not coersions to simple data types like strings or numbers. Thank you. -- Darren Duncan
Re: overloading the variable declaration process
On 2/6/06, Larry Wall [EMAIL PROTECTED] wrote: This is mostly motivated by linguistics rather than computer science, insofar as types/classes/roles in natural language are normally represented by generic objects rather than meta objects. When I ask in English: Can a dog bark? that's equivalent to asking in Perl 6: Dog.can('bark') That sentence is ambiguous. You can interpret it as: Can some dog bark? Or as: Can every dog bark? I think you meant the latter, however the sentence is leaning toward the former. Can dogs bark? would be less ambiguous in that respect. And while I'm starting to see the linguistic rationale behind this decision, I still can't find anything concrete that this buys us. Call me an American, but I like instant gratification. Luke
Re: overloading the variable declaration process
Larry~ On 2/6/06, Larry Wall [EMAIL PROTECTED] wrote: This is mostly motivated by linguistics rather than computer science, insofar as types/classes/roles in natural language are normally represented by generic objects rather than meta objects. When I ask in English: Can a dog bark? that's equivalent to asking in Perl 6: Dog.can('bark') Or you might think of it more as a question like Can the ideal of a dog bark? the answer to which is of course No, it doesn't exist.. Perhaps, I am just too firmly rooted in old paradigms but I think it is very important not to conflate the representation of a thing with the thing. http://en.wikipedia.org/wiki/Image:MagrittePipe.jpg Matt -- Computer Science is merely the post-Turing Decline of Formal Systems Theory. -Stan Kelly-Bootle, The Devil's DP Dictionary
overloading the variable declaration process
All, Speaking briefly, I would like it if Perl 6 provided a way for a class (or role, or meta-class, etc) to declare that all variables declared to be of that type are automatically/implicitly set to a particular value at declaration time, so that they are not undefined if the programmer using them doesn't explicitly set a value. Here are usage examples: my NumType $foo; # implicitly contains a defined NumType of value 0 my StrType $bar; # implicitly contains a defined StrType of value '' Sure, the user could say .= new() or such, but I wanted a fallback if they didn't do that. Then when they come to just use that not explicitly set variable, it contains some type-defined reasonable default value. Presumably, the object meta-model would have an appropriate function defined for use at that time, which returns undef by default, and this function is what individual classes can override. Part way through writing this, I had a brief chat on #perl6 with stevan (and apparently the meta-model is still quite in flux) and he said my question was related to Larry's class but undef idea, and that Larry should talk more about the subject. Thank you. -- Darren Duncan
Re: overloading the variable declaration process
On 2/6/06, Darren Duncan [EMAIL PROTECTED] wrote: Speaking briefly, I would like it if Perl 6 provided a way for a class (or role, or meta-class, etc) to declare that all variables declared to be of that type are automatically/implicitly set to a particular value at declaration time, so that they are not undefined if the programmer using them doesn't explicitly set a value. In a somewhat related note, Perl 6 allows this form: my Dog $fido .= new; which may be treated as a special form (as is currently the case with Pugs). However if it's not, it would desugar to: my Dog $fido; $fido = $fido.new; which seem to imply that $fido is set to ::Dog (the dog class) as its initial value. However, that would potentially make this a no-op: my Dog $fido = Dog; which may make sense except that defined($fido) may need to be regulated as true even for the my Dog $fido case. If so, your use case can be satisfied by declaring that ::NumType (the class object) numifies to 0, and ::StrType stringifies to , via the coerceas form. Audrey
Method overloading, MMD/SMD
In Synopsis 13 MMD is discussed as the mechanism for overloading an operator. Many a times I would like to overload a method of a class. I just played around with this: http://svn.openfoundry.org/pugs/modules/Class-Events/lib/Class/Events.pm Notice how the Named event variation appends the role, adding some more specific signatures to familiar functions, to increase dwimmery. How do i get this to behave? Do I need to say all the methods that can ever be overloaded are multi? Or do I say that only the overloading ones are multi? If the first - how do I get a delegation to be multi? Does that rely on the delegation handler method? Also, is SMD not possibly representable in MMD? Is SMD a subset of MMD or a completely different system? Also on a side note, say I have two roles, both of which define the private attribute $.:horse. Do these attributes conflict, or does each role get it's own slot? What about MI/mixins? Grazie -- () Yuval Kogman [EMAIL PROTECTED] 0xEBD27418 perl hacker /\ kung foo master: /me tips over a cow: neeyah!! pgpY3osGEiO6Z.pgp Description: PGP signature
Re: A6: overloading multis on constness of parameters
On Fri, Mar 14, 2003 at 01:45:56PM +1100, Damian Conway wrote: : Oh, and I was wrong to originally write: Cmulti *isa ... Sorry, you're not even wrong. :-) : Multimethods live in their own namespace. No * required. Alternately, we require the C* in order to accurately document their scope. And I do think they live in C*. Otherwise we need to come up with yet another name for the global scope that happens to contain multimethods. An argument can also be made that we should do that anyway on the grounds that we might someday have scoped multi-methods of some kind or other. I suppose can allow a Csub * in the same scope as Cmulti * for the case that you want a global override of all the multimethods. It just looks for the sub first. If that sub then wants to redispatch to the multimethods, it'd have to use some special multimethod syntax that doesn't look like a sub invocation, such as the notional ($a,$b,$c) forwhich foo() we talked about in Sebastopol, however we end up spelling forwhich. It's really a kind of postpositional topicalizer for the following predicate. English doesn't really have any good ones of those. If I were Japanese, I'd spell it wa or ga or no. Well, okay, I'd actually spell it or or if I were *really* Japanese. :-) Larry
Re: A6: Assignment Overloading
On Fri, Mar 14, 2003 at 01:20:28PM +1100, Damian Conway wrote: : Luke Palmer wrote: : : So, now that we have binding, is it possible to overload the : assignment operator? : : Not really. The problem is that Cinfix:= is really an operator on : *containers*, not on *values*. So, in order to overload C=, you'll still : need to define an appropriate CSTORE method on the appropriate : implementation class for the container. Whether CSTORE can also be : spelled Cinfix:= is another question. : : : Does the assignment operator mean value copy : instead of reference copy? : : The assignment operator means copy rhs's value into lhs's container. : The binding operator means copy (reference to) rhs's container into lhs's : symbol table entry. Note that assignment is a very shallow copy in any event. Intrinsic types are copied by default, plus any objects with a .copy method. In other words, Scalar has a .copy method by default, and anything else is your own doing. Int, Num, Str, and Ref inherit the .copy interface from Scalar. In particular, a Ref only copies itself unless it refers to something with a .copy method. In other words, the .copy method defines it as an intrinsic scalar type. That's exactly how it works, bearing in mind that any or all of the details might be wrong. Larry
A6: Assignment Overloading
So, now that we have binding, is it possible to overload the assignment operator? Does the assignment operator mean value copy instead of reference copy? Luke
Re: A6: overloading multis on constness of parameters
Piers Cawley wrote: Speaking of multis and constants, Greg McCarroll wondered on IRC if this would work: multi factorial (Int 0) { 1 } multi factorial (Int $n) { $n * factorial($n-1) } Probably not. We did discuss whether multimethods should be able to be overloaded by value, but concluded (for that week, at least ;-) that this might prove syntactically excessive. Besides which, since multimethod dispatch will have to use Cisa to determine type compatibility on parameters anyway, it's trivial to implement this form of value-based dispatch yourself: class Zero { multi *isa ($obj, Zero $class) { $obj ~~ 0 } } # and then... multi factorial (IntZero $g) { 1 } or, supposing we have some form of parameterized types, you could create something more generic like: class Val($N) { multi *isa ($obj, Val($N) $class) { $obj ~~ $N } } # and then... multi factorial (IntVal(0) $g) { 1 } ;-) Damian
Re: A6: Assignment Overloading
Luke Palmer wrote: So, now that we have binding, is it possible to overload the assignment operator? Not really. The problem is that Cinfix:= is really an operator on *containers*, not on *values*. So, in order to overload C=, you'll still need to define an appropriate CSTORE method on the appropriate implementation class for the container. Whether CSTORE can also be spelled Cinfix:= is another question. Does the assignment operator mean value copy instead of reference copy? The assignment operator means copy rhs's value into lhs's container. The binding operator means copy (reference to) rhs's container into lhs's symbol table entry. Damian
Re: A6: overloading multis on constness of parameters
or, supposing we have some form of parameterized types, you could create something more generic like: class Val($N) { multi *isa ($obj, Val($N) $class) { $obj ~~ $N } } # and then... multi factorial (IntVal(0) $g) { 1 } Yes, YES! Marvelous! Not that that couldn't be done with a closure anyway... { my Class %valClasses; sub Val($N) returns Class { my Class $rclass = %valClasses{$N} //= class { multi *isa ($obj, $rclass $class) { $obj ~~ $N } } } } multi factorial (Int Val(0) $g) { 1 } Hmm, would Val(0) be evaluated at compile-time in that case... or must I mark it with some sort of trait, or do some other kind of trick. Cool, anyhow. Luke
Re: A6: overloading multis on constness of parameters
Luke Palmer wrote: Not that that couldn't be done with a closure anyway... { my Class %valClasses; sub Val($N) returns Class { my Class $rclass = %valClasses{$N} //= class { multi *isa ($obj, $rclass $class) { $obj ~~ $N } } } } multi factorial (Int Val(0) $g) { 1 } I don't think so. I seriously doubt you can put a run-time-evaluated sub call in a type specification visions of Dan fainting in horror ;-) A Cmacro might do the trick though. Oh, and I was wrong to originally write: Cmulti *isa ... Multimethods live in their own namespace. No * required. Damian
Re: A6: overloading multis on constness of parameters
On Wed, Mar 12, 2003 at 01:35:08PM +1100, Damian Conway wrote: : Joe Gottman wrote: : :Will it be possible in perl6 to overload multis on the const-ness of a : parameter, like C++ does? For instance, : :multi getX(Foo $self:) returns Int {...} #const version :multi getX(Foo $self: is rw) returns Int is rw {...} #non-const version : : That second one would have to be: : : multi getX(Foo $self is rw:) returns Int is rw {...} : : : Then we have the issue that Perl 6 objects can't really be constant, : since Cis constant is a compile-time trait of *containers*...really just : a don't assign to this container marker. : : However, within those limitations, I guess it's possible. After all, we : have to check for lvaluability of Cis rw parameters anyway. Might be one of those things that is taken as a tie-breaker, all other things being equal. I'm thinking return types fall into the same category. Larry