Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
I think that Jonathan meant for his reply to my message to go to the list, so I am including it in its entirety, in my reply. At 11:23 PM -0700 7/13/06, Jonathan Lang wrote: Darren Duncan wrote: Jonathan Lang wrote: So the purpose of === is to provide a means of comparison that doesn't implicitly coerce its arguments to a particular type? Yes, absolutely. The === takes 2 arguments exactly as they are, without changing anything, and says if they are two appearances of the same value. It would always return false if the 2 arguments are of different declared types. And if they are of the same types, then no coersion is necessary in order to compare them for equality. So the difference between eqv and === is: @a eqv @b iff all(for each(@a, @b) - $a, $b { $a === $b }) # a deep comparison or @a === @b iff all(for each(@a, @b) - $a, $b { $a =:= $b }) # a shallow comparison ? That seems counterintuitive to me; I'd rather see both === and eqv represent a deep comparison, and leave shallow comparisons to less elegant approaches. I see eqv and === as both being recursive with their own kinds when used on any and immutable data types respectively. Arrays are mutable, so I see that the above examples mean the following (only relevant parts changed, other syntax parts may be wrong): @a eqv @b iff all(for each(@a, @b) - $a, $b { $a eqv $b }) # a deep comparison using eqv all along @a === @b iff @a =:= @b # a shallow comparison since === only tests immutable aspects Now, lets try two Seq, $a and $b, instead, which are like Array but immutable: $a === $b iff all(for each($a.values, $b.values) - $a, $b { $a === $b }) # a deep-as-possible comparison using === all along Assuming that all elements of $a and $b are themselves immutable to all levels of recursion, === then does a full deep copy like eqv. If at any level we get a mutable object, then at that point it turns into =:= (a trivial case) and stops. Note that if your Seqs just contain other immutable things like Str or Int or Set or Pair or Mapping etc to all recursion levels, which they are highly likely to do, then === is simply a deep recursion. That's how I understand it, and it seems quite elegant and simple. -- Darren Duncan
optimizing with === immutable comparitor
This may go without saying, but ... If $a === $b means what I think it does, then I believe that a not-premature implementation optimization of === would be that it always $a := $b if it was returning true, so that any future === of $a and $b or aliases thereof could short-circuit with a =:= test even if they weren't created as aliases, and Perl would be automatically more memory efficient without those extra storage copies. I know that was an implementation issue, but I think that it stands to be explicitly stated anyway, as it is a very simple and effective way to make Perl programs more resource efficient, possibly by orders of magnitude, over not doing so. (The only time this may not work is if so-called immutable types are tied to external resourses, but then I'm not sure how often this would happen in practice so it could just be an exception if necessary. The above-stated rule would still stand for any resources managed by Perl itself.) -- Darren Duncan
Re: optimizing with === immutable comparitor
On Friday 14 July 2006 00:30, Darren Duncan wrote: This may go without saying, but ... If $a === $b means what I think it does, then I believe that a not-premature implementation optimization of === would be that it always $a := $b if it was returning true, so that any future === of $a and $b or aliases thereof could short-circuit with a =:= test even if they weren't created as aliases, and Perl would be automatically more memory efficient without those extra storage copies. I know that was an implementation issue, but I think that it stands to be explicitly stated anyway, as it is a very simple and effective way to make Perl programs more resource efficient, possibly by orders of magnitude, over not doing so. First there was copy-on-write and now there's share-on-compare? (The only time this may not work is if so-called immutable types are tied to external resourses, but then I'm not sure how often this would happen in practice so it could just be an exception if necessary. The above-stated rule would still stand for any resources managed by Perl itself.) In the absence of much Perl 6 code either way, I wonder at the value of adding such an extreme side effect to a simple comparison operation. This goes way beyond loop hoisting and constant folding. I can understand singleton value types (even Perl 5 does that with PL_undef), but ... wow, you have a lot more faith in local code analysis than I do. -- c
CORRECTION: optimizing with === immutable comparitor
At 12:30 AM -0700 7/14/06, Darren Duncan wrote: If $a === $b means what I think it does, then I believe that a not-premature implementation optimization of === would be that it always $a := $b if it was returning true, so that any future === of $a and $b or aliases thereof could short-circuit with a =:= test even if they weren't created as aliases, and Perl would be automatically more memory efficient without those extra storage copies. Sorry, I stated some things badly in that previous email, mainly the $a := $b part, which is technically incorrect, so I will try and clarify what I meant to say. What I propose concerning non-premature === optimizing is a system where, at any time that two appearances of the same immutable value are compared with ===, they are immediately consolidated into a single appearance. Or at least $a.value := $b.value occurs immediately, and garbage collection of the second and now unreferenced copy happens whenever it would happen. For illustration: $a = 'hello'; # one copy of the value 'hello' in memory $b = 'hello'; # a second copy of the value 'hello' elsewhere in memory $c = 'world'; # one copy of 'world' in memory $a === $b; # now only one copy of 'hello' is in memory, $a and $b point to $a === $c; # nothing changes, as values are different $b = $c; # now only $a points to 'hello', $b and $c point to one 'world' I of course did not mean for the actual symbol $a := $b to happen, only what they point to internally. Of course, the above example could be constant folded to one copy of 'hello' at compile time, but my illustration is meant to be for situations where $a and $b are declared or set far apart, possibly from run-time input values, so the folding happens at run time. What I meant with the =:= shortcut then, is that $a.value =:= $b.value could return true following the above run of $a === $b. Sorry for any confusion. FYI, I plan to explicitly illustrate the principle in my next Set::Relation update, since its types are immutable, so that any operations which involve comparing two relations or tuples or headings or values therein with === will have a side-effect of consolidating them if they are equal. Later on, if this happens at the language level, I would less likely have to do it myself. -- Darren Duncan
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
Yuval Kogman writes: So, Larry assisted by Audrey explained the purpose of === vs eqv vs =:=. I'm afraid I still don't get it. Or rather, while I can manage to read an explanation of what one of these operators does and see how it applies to the variables in the examples next to it, I am struggling to retain a feeling of _why_ I would want to use any of these operators in real-life Perl 6 code. Please could the proponets of the various behaviours being discussed here share a few more concrete examples which start by explaning a scenario in which there is a desire to do something, preferably one that Perl 5 coders can identify with, and then show how one of these new operators would meet that desire (and that without that operator it would be hard or clumsy to achieve the same thing)? Already in Perl 5 having 2 different equality operators is something that learners often stumble over. If we're going to have 5 of the things in Perl 6 then there needs to be a very clear way of explaining how to determine which one to use (or at least an explanation that 3 of the operators are very esoteric and beginners don't need to worry about them). Smylers
Re: CORRECTION: optimizing with === immutable comparitor
Darren Duncan schreef: What I propose concerning non-premature === optimizing is a system where, at any time that two appearances of the same immutable value are compared with ===, they are immediately consolidated into a single appearance. That should only be done voluntarily. A bit like memoization. Something else: An immutable composite value can have unfinalized parts. Finalizing them for the sake of a deep comparison, can hurt performance. Does a lazy system need something like 'undecided' or 'NaB' (not-a-boolean)? -- Groet, Ruud
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On Fri, Jul 14, 2006 at 11:42:24 +0100, Smylers wrote: I'm afraid I still don't get it. Or rather, while I can manage to read an explanation of what one of these operators does and see how it applies to the variables in the examples next to it, I am struggling to retain a feeling of _why_ I would want to use any of these operators in real-life Perl 6 code. To compare deep structures ;-) Already in Perl 5 having 2 different equality operators is something that learners often stumble over. But only for low level types. To see if two objects are the same, or two hashes, you need to use Data::Compare, or to overload either == or eq, neither of which is a perfect fit. I have to catch my flight, so I'll explain more later. -- Yuval Kogman [EMAIL PROTECTED] http://nothingmuch.woobling.org 0xEBD27418 pgp4zdMSoN13m.pgp Description: PGP signature
Re: optimizing with === immutable comparitor
On Fri, Jul 14, 2006 at 00:30:20 -0700, Darren Duncan wrote: This may go without saying, but ... ... This is a VM issue. It clarifies semantics, and the runtime VM may choose to do this freely for simple values (but not for objects which just pretend using .id). In short: yes, the semantics allow that, but it has nothing to do with the language it might not even be faster. -- Yuval Kogman [EMAIL PROTECTED] http://nothingmuch.woobling.org 0xEBD27418 pgp2roLoyDefj.pgp Description: PGP signature
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
Yuval Kogman writes: On Fri, Jul 14, 2006 at 11:42:24 +0100, Smylers wrote: Or rather, while I can manage to read an explanation of what one of these operators does and see how it applies to the variables in the examples next to it, I am struggling to retain a feeling of _why_ I would want to use any of these operators in real-life Perl 6 code. To compare deep structures ;-) Thank you. That helps. My initial instinct was that this meant the new operators can all be dismissed as ignorable by learners, as they won't be using nested data structures anyway. But actually deep doesn't have to be very deep in order for such a comparison op to have use: merely wanting to see if the contents of 2 arrays are the same doesn't involve any nesting and is a concept that is well within the grasp of a beginner. so I'll explain more later. Great. I appreciate your help, and I'm looking forward to your explanation of the different behaviours in this thread. Smylers
Re: Run time dispatch on ~~
On Fri, 2006-07-14 at 00:08 +0300, Yuval Kogman wrote: Also, sometimes i am matching on behalf of my caller, this is very common in dispatch algorithms, or things like tree visitors: my @list = $tree.filter_children( $match ); # very generic and useful It's really the fact that that's a method that hoses everything. There's essentially no way to compile-time dispatch that, so even macros won't help you grr. No, you've got me. There needs to be a way to do that, but oh dear it's going to be confusing, and as ever, I worry about those who will use this sort of thing poorly or mistakenly, and then rant on about how Perl is write-only. Perhaps the solution is not code, but documentation. Perhaps if we make a clean break between comparison and matching in the docs, and push people away from non-regex/string-~~ until they understand its implications, we can head off much of the lossage. For example (modified S03 Smart matching section without the table): =head1 Smart matching Smart matching is the process of asking, does thing Ia conform to the specification of Ib? The most common reason to want to do this is to match a string against a regex: if $s ~~ /^\d+$/ { ... } But smart matching is also performed by given/when for switch-like behavior: given $s { when 'Apple' { ... } when 'Pear' { ... } default { die No fruit! } } Notice that the specification can also be a string, as above, but because Ceqv and C~~ mean the same thing in this context, it is clearer, when writing a single expression to explicitly use Ceqv: if $a eqv $b { ... } The right-hand side of C~~ (the specification) always controls the nature of the matching, so care must be taken when matching. Do not think of this as simple comparison where the arguments are considered peers. Here is the current table of smart matches with respect to $_ and $x as they would be used here: given $_ { when $x {...} } or $_ ~~ $x The list is intended to reflect forms that can be recognized at compile time. If none of these forms is recognized at compile time, it falls through to do MMD to C infix:~~() , which presumably reflects similar semantics, but can finesse things that aren't exact type matches. Note that all types are scalarized here. Both C~~ and Cgiven/Cwhen provide scalar contexts to their arguments. (You can always hyperize C~~ explicitly, though.) Both C$_ (the value) and C$x (the match specification) here are potentially references to container objects. And since lists promote to arrays in scalar context, there need be no separate entries for lists. (table goes here) -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith We had some good machines, but they don't work no more. -Shriekback
Re: Run time dispatch on ~~
Aaron Sherman schreef: given $_ { when $x {...} } or $_ ~~ $x Can that be written as .~~ $x? -- Affijn, Ruud Gewoon is een tijger.
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
Darren Duncan wrote: Now, I didn't see them yet anywhere in Synopsis 3, but I strongly recommend having negated versions of all these various types of equality tests. Eg, !== for ===, nev for eqv, etc. They would be used very frequently, I believe (and I have even tried to do so), and of course we get the nice parity. Yes and they should be strictly implicitly defined in term of the positive versions in such a way that you can't explicitly redefine them separately. I.e., $x !== $y should always mean exactly the same thing as !($x === $y). Maybe by a macro definition. To do otherwise would be very confusing as it would make such simple program transformations as: say foo if $x !== $y; into say foo unless $x === $y; very unreliable. Actually a similar argument could be made about '' vs '', '=' and '=' in other words just redefining '==' '' should automatically get you '!=', '=', '=' and ''. -- [EMAIL PROTECTED] [EMAIL PROTECTED]
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
Darren Duncan wrote: Assuming that all elements of $a and $b are themselves immutable to all levels of recursion, === then does a full deep copy like eqv. If at any level we get a mutable object, then at that point it turns into =:= (a trivial case) and stops. ( 1, 2.0, 3 ) === ( 1,2,3 ) True or false? More imprtantly, how do I tell perl what I mean? The best I can think of is: [] (@a »==« @b) Vs [] (@a »eq« @b) But this only works for nice flat structures. For arbitrary tree structures, we probably need adverbs on a comparison op (I think Larry mentioned this a few posts back) ... but if we're going with adverbs do we really need 5 different base operators? Are all of the 5 so common that it would be clumbersome to require adverbs for their behavior? Also, when sorting things, maybe deep inequalities would be useful, too.
Re: Run time dispatch on ~~
On Fri, Jul 14, 2006 at 04:34:26PM +0200, Dr.Ruud wrote: : Aaron Sherman schreef: : : given $_ { : when $x {...} : } : : or : : $_ ~~ $x : : Can that be written as .~~ $x? No, but you might just possibly get away with writing: .infix:~~($x) assuming that the $_.foo($x) SMD eventually fails over to foo($_,$x) MMD. But that doesn't seem to be much of an improvement over when $x. Larry
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
Mark A. Biggar schreef: Darren Duncan: Now, I didn't see them yet anywhere in Synopsis 3, but I strongly recommend having negated versions of all these various types of equality tests. Eg, !== for ===, nev for eqv, etc. They would be used very frequently, I believe (and I have even tried to do so), and of course we get the nice parity. Yes and they should be strictly implicitly defined in term of the positive versions in such a way that you can't explicitly redefine them separately. I.e., $x !== $y should always mean exactly the same thing as !($x === $y). Maybe by a macro definition. To do otherwise would be very confusing as it would make such simple program transformations as: say foo if $x !== $y; into say foo unless $x === $y; And how about symmetry: say foo unless $y === $x; very unreliable. -- Affijn, Ruud Gewoon is een tijger.
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
At 9:22 AM -0700 7/14/06, Dave Whipp wrote: Darren Duncan wrote: Assuming that all elements of $a and $b are themselves immutable to all levels of recursion, === then does a full deep copy like eqv. If at any level we get a mutable object, then at that point it turns into =:= (a trivial case) and stops. ( 1, 2.0, 3 ) === ( 1,2,3 ) True or false? That would be false, because a Str does not === an Int. I should point out, though, that in at least some situations where you are ===, you would have more control of the creation of the structures in the first place and they will probably have been created in a more strict fashion that required the data to be of corresponding types in the first place. Eg, each Seq would have only been allowed to store Ints in the first place. The best place to normalize input is as early as possible, after all, like when the Ints were input and before they were put in the Seq to be compared. More imprtantly, how do I tell perl what I mean? The best I can think of is: [] (@a »==« @b) Vs [] (@a »eq« @b) But this only works for nice flat structures. For arbitrary tree structures, we probably need adverbs on a comparison op (I think Larry mentioned this a few posts back) ... but if we're going with adverbs do we really need 5 different base operators? Are all of the 5 so common that it would be clumbersome to require adverbs for their behavior? Also, when sorting things, maybe deep inequalities would be useful, too. I will punt on that one. -- Darren Duncan
Fwd: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
Dave Whipp wrote: Darren Duncan wrote: Assuming that all elements of $a and $b are themselves immutable to all levels of recursion, === then does a full deep copy like eqv. If at any level we get a mutable object, then at that point it turns into =:= (a trivial case) and stops. ( 1, 2.0, 3 ) === ( 1,2,3 ) True or false? More imprtantly, how do I tell perl what I mean? The best I can think of is: [] (@a »==« @b) Vs [] (@a »eq« @b) But this only works for nice flat structures. IIRC, this is because the implicit coercion to number or string gets in the way. IMHO, @a == @b ought to be synonymous with all (@a »==« @b) - it's far more likely to DWIM. Likewise with @a eq @b and all (@a »eq« @b). If what you want to do is to compare the lengths of two lists, you ought to do so explicitly: [EMAIL PROTECTED] == [EMAIL PROTECTED]. Getting back to the notion of immutability: can someone give me an example of a realistic immutable analog to a list, and then give an example demonstrating the practical distinction between === and eqv based on that? I want to see why it's important to distinguish between comparing mutable data types and comparing immutable data types. (Incidently, I think that a suitable word-based synonym for =:= would be is.) -- Jonathan Dataweaver Lang
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
At 6:55 PM +0200 7/14/06, Dr.Ruud wrote: say foo if $x !== $y; into say foo unless $x === $y; And how about symmetry: say foo unless $y === $x; very unreliable. Any equality or inequality operator is commutative, so it doesn't matter whether you have $x and $y or $y and $x, the result is the same. So you can use whichever order you want without it needing to be coded for. -- Darren Duncan
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On Thu, Jul 13, 2006 at 10:56:59PM -0700, Darren Duncan wrote: : Now, I didn't see them yet anywhere in Synopsis 3, but I strongly : recommend having negated versions of all these various types of : equality tests. Eg, !== for ===, nev for eqv, etc. They would be : used very frequently, I believe (and I have even tried to do so), and : of course we get the nice parity. My gut feeling contradicts yours--I think these are going to be far rarer in practice than == and eq, so they don't warrant yet more special forms that have to be memorized. And !== is too easy to confuse with != visually, or with !(==) semantically. For such long operators, I'd try to do exact syntactical composition rather than replacement, so they'd be !=== and neqv, probably, along with !=:=. Maybe even go with !eqv rather than neqv, and make ! into a metaoperator on relationals. Then !== and !eq would be identical to != and ne. But a lot of the time the negated versions are going to be disallowed anyway, simply because English mangles junctions when it does not raising. Valid English: If X doesn't equal one or two or three, say out of range. Naïve Perl: if $x != 1 | 2 | 3 { say out of range; } But that's wrong because Perl doesn't do not raising, so the statement above always prints out of range. You should have said one of: if not $x == 1 | 2 | 3 { say out of range; } if $x != 1 2 3 { say out of range; } So either we have to make Perl do not-raising like English, which will probably confuse non-English speakers, or we have to disallow negative operators from participating in junctional logic, or we have a huge educational problem (read FAQ). My money is currently on disallowing distribution of junctions over negated operators, and forcing people to do not-raising explicitly, at least in the syntactic case above. Perhaps we can still allow the semantics where it's not likely to be confused with English. Anyway, that's just another reason for going slow on throwing in the negated versions. Larry
Re: Run time dispatch on ~~
Larry Wall schreef: Dr.Ruud: Aaron Sherman: $_ ~~ $x Can that be written as .~~ $x? No, but you might just possibly get away with writing: .infix:~~($x) assuming that the $_.foo($x) SMD eventually fails over to foo($_,$x) MMD. But that doesn't seem to be much of an improvement over when $x. OK, thanks. Is it ever useful for an SMD to fail over to MMD? -- Affijn, Ruud Gewoon is een tijger.
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
At 12:55 PM -0700 7/14/06, Larry Wall wrote: On Thu, Jul 13, 2006 at 10:56:59PM -0700, Darren Duncan wrote (edited): : Now, I didn't see them yet anywhere in Synopsis 3, but I strongly : recommend having negated versions of all these various types of : equality tests. Eg, !=== for ===, !eqv for eqv, etc. They would be : used very frequently, I believe (and I have even tried to do so), and : of course we get the nice parity. My gut feeling contradicts yours--I think these are going to be far rarer in practice than == and eq, so they don't warrant yet more special forms that have to be memorized. Actually, now that I think about it, I could use 'not' to avoid a lot of the syntactic hassle that I've been having with a lack of !===. Eg, what I wanted was to avoid having to say: if (!($foo === $bar) and ...) { ... } So I had proposed instead: if ($foo !=== $bar and ...) { ... } But then your post reminded me of 'not', and since it binds tighter than 'and' and 'or', I can say: if (not $foo === $bar and ...) { ... } While I still like the second example best, in light of the issues of not-raising you mention that could confuse others, I'll withdraw my request for now. -- Darren Duncan
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On Fri, Jul 14, 2006 at 09:22:10 -0700, Dave Whipp wrote: Darren Duncan wrote: Assuming that all elements of $a and $b are themselves immutable to all levels of recursion, === then does a full deep copy like eqv. If at any level we get a mutable object, then at that point it turns into =:= (a trivial case) and stops. ( 1, 2.0, 3 ) === ( 1,2,3 ) True or false? false More imprtantly, how do I tell perl what I mean? The best I can think of is: [] (@a »==« @b) Vs [] (@a »eq« @b) Neither - it's on the natural types. If the types are different it's != -- Yuval Kogman [EMAIL PROTECTED] http://nothingmuch.woobling.org 0xEBD27418 pgpdVijcRjp0Q.pgp Description: PGP signature
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
Darren Duncan schreef: Dr.Ruud: say foo if $x !== $y; into say foo unless $x === $y; And how about symmetry: say foo unless $y === $x; Any equality or inequality operator is commutative, If $x and $y are not of the same type, and one or both of the involved types has its own (or overloaded?) 'deep equality operator', the choice (which implementation is used) can depend on the order. Not so long ago, there was an issue with Perl5 in this area (IIRC with '==' and undef). so it doesn't matter whether you have $x and $y or $y and $x, the result is the same. So you can use whichever order you want without it needing to be coded for. -- Darren Duncan -- Affijn, Ruud Gewoon is een tijger.
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On 7/14/06, David Green [EMAIL PROTECTED] wrote: On 7/13/06, Yuval Kogman wrote: So, Larry assisted by Audrey explained the purpose of === vs eqv vs =:=. It makes sense now, but I still feel that as far as ergonomics go this is not perfect. I think I understand it... (my only quibble with the syntax is that === and eqv look like spin-offs of == and eq, but I don't know what to suggest instead (we're running short of combinations of = and : !)) So there are three basic kinds of comparison: whether the variables are the same (different names, but naming the same thing); whether the values are the same (deep comparison, i.e. recursively all the way down in the case of nested containers); and in-between (shallow comparison, i.e. we compare the top-level values, but we don't work out *their* values too, etc., the way a deep comparison would). If I've got it right, this is what =:=, eqv, and === give us, respectively. It may well be that I'm misunderstanding here -- I've been away from Perl development for too long and have a lot of catching up to do -- but I'm uneasy about using the terms shallow comparison and immutably equal to describe the same thing. If the true meaning of $a === $b is that $a.id eq $b.id, where .id is the value for a simple type, I think it'd be least confusing to just call it a shallow comparison. Immutable equality sounds more like a promise of deep and lasting equality, not an assertion that equality is skin deep. I make a similar inference from the long sigil -- it has more the flavor of more equal than a special case of equal (to me, at least). Just to muddy the waters further, I'd think -- off the cuff -- that you might do well with expectations to say == and eq - shallow comparison of numeric and string values, specifically (with other types being free to specify what their numeric and string values are -- caveat usor) Matches existing expectations of these operators === - deeply equal (equivalent to the current eqv); alias for isreally or isdeeply Expectation based on extending the == metaphor eqv - Different names for the same thing (what I think =:= means now) Expectation based on glossing as equivalent rather than equal value. =:=- Defined identically, with no promise about contents (what I think === means now). Expectation based on the use of : to indicate declaratory behavior Just two cents from a Perl6 newbie. -- Regards, Charles Bailey Lists: bailey _dot_ charles _at_ gmail _dot_ com Other: bailey _at_ newman _dot_ upenn _dot_ edu
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On Thu, Jul 13, 2006 at 10:19:24PM -0600, David Green wrote: : On 7/13/06, Yuval Kogman wrote: : So, Larry assisted by Audrey explained the purpose of === vs eqv vs =:=. : It makes sense now, but I still feel that as far as ergonomics go : this is not perfect. : : I think I understand it... (my only quibble with the syntax is that : === and eqv look like spin-offs of == and eq, but I don't know what : to suggest instead (we're running short of combinations of = and : !)) That's partly because they *are* spinoffs, on a metaphorical level. The === operator is a mathematically equal, where that implies equality henceforth and forevermore. There is also a bit of the notion that, since a number is a singular thing, you can't treat any of the bits of a number as mutable. There's no lvalue substr() defined on a number, as it were. The eqv operator, on the other hand, is a you have to work at figuring this out by serializing both values conceptually to canonical strings (think Storable) and see if those are eq. (Only you don't really go to all that work, if you can short circuit any of it.) There is also the notion (though this breaks down if you look at it too hard) that a string can be modified in place, so a string value is mutable (at least from the standpoint of the variable holding it; from the standpoint of ===, string values are immutable, which is where the analogy breaks down). : So there are three basic kinds of comparison: whether the variables : are the same (different names, but naming the same thing); whether : the values are the same (deep comparison, i.e. recursively all the : way down in the case of nested containers); and in-between (shallow : comparison, i.e. we compare the top-level values, but we don't work : out *their* values too, etc., the way a deep comparison would). If : I've got it right, this is what =:=, eqv, and === give us, : respectively. No, === is also deep. It's only shallower (or potentially shallower) in the sense that it treats any mutable object node as a leaf node rather than changing to snapshot semantics like eqv does. : (When I say value I'm thinking of everything that makes up the : value, such as type (so the number 3 is different from the string : 3), or details like the encoding for a string, etc.) Arguably the encoding of a string has nothing to do with its value most of the time, if the semantics are supposed to be consistent Unicode semantics at the codepoint or grapheme level. But yes, by and large types do have to be included. Bool::True is a different value from 1, even though they are often interchangable in many contexts. : Examples: : : @x=foo bar; : @y=foo bar; : : $a=[1, 2, [EMAIL PROTECTED]; : $b:=$a; : $c=[1, 2, [EMAIL PROTECTED]; : $d=[1, 2, [EMAIL PROTECTED]; : : : $a =:= $b; #true, same variable with two names : $a === $b; #true _/ $b just another name for $a, : $a eqv $b; #true\ so comparable at all levels : : $a =:= $c; #false, different variables : $a === $c; #true, same elements make up $a and $c : $a eqv $c; #true, same elements therefore same values : : $a =:= $d; #false, different variables : $a === $d; #false, [EMAIL PROTECTED] and [EMAIL PROTECTED] are different refs : $a eqv $d; #true, values of @x and @y happen to be the same All correct. : (Of course, @x eqv @y, @[EMAIL PROTECTED], but not @x=:[EMAIL PROTECTED]) : Note that if $i=:=$j, then $i===$j; and of course if $i===$j, then $i eqv : $j. Those are necessarily true, assuming nobody else is meddling with our data structures in the middle of our comparison. If someone is modifying some mutable component in $i or $j while we're taking a snapshot, then we can get into inconsistent states where eqv can return false despite === being true. : OK, looking at S03 again, that still isn't correct. I think my =:= : and eqv are all right, but I don't understand exactly what === is : supposed to do, or why it's useful. And how do I do my : shallow-comparison above? S03 hasn't been updated to reflect all this yet. === semantics are useful for figuring out whether you have a unique key for a hash when you want to hash on live objects. eqv is for dead keys, because as soon as you've taken a snapshot of your data, you can't modify the snapshot or dereference any object in your hash key. eqv semantics are what Perl 5 hashes use for keys, which is why you can't deref a hash key directly even if you thought you were putting an object in as the key. : (One [1,2] is as good as any other [1,2] -- what's the use of ever : having them not compared as the same? I can see maybe for =:=, since : something that doesn't have a name cannot, by definition, have the : same name as something else... although even there, it arguably makes : sense to consider equivalent anonymous values as bound to the same : place. There's only one unique [1,2] in
[svn:perl6-synopsis] r10215 - doc/trunk/design/syn
Author: larry Date: Fri Jul 14 17:00:12 2006 New Revision: 10215 Modified: doc/trunk/design/syn/S03.pod Log: Differentiate === from eqv and clarify semantics. Redefine cmp and add leg operator for old semantics. Add ! metaoperator. Fix random typos. Modified: doc/trunk/design/syn/S03.pod == --- doc/trunk/design/syn/S03.pod(original) +++ doc/trunk/design/syn/S03.podFri Jul 14 17:00:12 2006 @@ -12,9 +12,9 @@ Maintainer: Larry Wall [EMAIL PROTECTED] Date: 8 Mar 2004 - Last Modified: 12 Jul 2006 + Last Modified: 14 Jul 2006 Number: 3 - Version: 46 + Version: 47 =head1 Changes to existing operators @@ -158,7 +158,7 @@ Operators that imply list operations are excluded: prefix C@, prefix C% and infix Cxx, for instance. Hyper operators are -also excluded, but post-assigment forms such as CSIMPLE += SIMPLE +also excluded, but post-assignment forms such as CSIMPLE += SIMPLE are allowed. All other forms imply parsing as a list assignment, which may or may not @@ -317,22 +317,24 @@ side for definedness instead of truth. There is a low-precedence form, too: Cerr. -=item * Binary C=== tests type and value correspondence: for two value types, -tests whether they are the same value (eg. C1 === 1); for two reference -types, checks whether they have the same identity value. For reference -types that do not define an identity, the reference itself is used (eg. it -is not true that C[1,2] === [1,2], but it is true that C@a === @a). - -Any reference type may pretend to be a value type by defining a C.id method -which returns a built-in value, i.e. an immutable object or a native value, -as specified in S06. - -Because Perl 6 uses a false C.id to signify a non-instantiated prototype, -all instances should arrange to return a C.id that boolifies to true. - -A class may also overload C infix:=== for more efficient comparison of -any two objects of that type, but it must return the same result as if -the two identity values had been generated and compared. +=item * Binary C=== tests immutable type and value correspondence: +for two value types (that is, immutable types), tests whether +they are the same value (eg. C1 === 1); for two mutable types +(object types), checks whether they have the same identity value. +(For most such types the identity is simply the reference itself.) +It is not true that C[1,2] === [1,2] because those are different +Array objects, but it is true that C@a === @a because those are +the same Array object). + +Any object type may pretend to be a value type by defining a C.id +method which returns a value type that can be recursively compared +using C===, or in cases where that is impractical, by overloading +C=== such that the comparison treats values consistently with their +eternal identity. (Strings are defined as values this way despite +also being objects.) + +(Because Perl 6 uses a false C.id to signify a non-instantiated prototype, +all instances should arrange to return a C.id that boolifies to true.) Two values are never equivalent unless they are of exactly the same type. By contrast, Ceq always coerces to string, while C== always coerces to @@ -342,7 +344,44 @@ Note also that, while string hashes use Ceq semantics by default, object hashes use C=== semantics. -=item * Binary C = is no longer just a fancy comma. It now +=item * Binary Ceqv tests equality much like C=== does, but does +so with snapshot semantics rather than eternal semantics. For +top-level components of your value that are of immutable types, Ceqv +is identical in behavior to C===. For components of your value +that are mutable, however, rather than comparing object identity using +C===, the Ceqv operator tests whether the canonical representation +of both subvalues would be identical if we took a snapshot of them +right now and compared those (now-immutable) snapshots using C===. + +If that's not enough flexibility, there is also an Ceqv() function +that can be passed additional information specifying how you want +canonical values to be generated before comparison. This gives +Ceqv() the same kind of expressive power as a sort signature. +(And indeed, the Ccmp operator from Perl 5 also has a functional +analog, Ccmp(), that takes additional instructions on how to +do 3-way comparisons of the kind that a sorting algorithm wants.) +In particular, a signature passed to Ceqv() will be bound to the +two operands in question, and then the comparison will proceed +on the formal parameters according to the information contained +in the signature, so you can force numeric, string, natural, or +other comparisons with proper declarations of the parameter's type +and traits. If the signature doesn't match the operands, Ceqv() +reverts to standard Ceqv comparison. (Likewise for Ccmp().) + +=item * Binary Ccmp is no longer the comparison operator that +forces stringification. Use the Cleg
Re: [svn:perl6-synopsis] r10215 - doc/trunk/design/syn
At 5:00 PM -0700 7/14/06, [EMAIL PROTECTED] wrote: Author: larry Date: Fri Jul 14 17:00:12 2006 New Revision: 10215 Modified: doc/trunk/design/syn/S03.pod Log: Differentiate === from eqv and clarify semantics. Redefine cmp and add leg operator for old semantics. Add ! metaoperator. Fix random typos. Larry, this new version looks great. A few small omissions or clarifications though ... +=item * Binary Ccmp is no longer the comparison operator that +forces stringification. Use the Cleg operator for the old Perl 5 +Ccmp semantics. The Ccmp is just like the Ceqv above except that +instead of returning CBool::False or CBool::True values it always +returns COrder::Increase, COrder::Same, or COrder::Decrease +(which numerify to -1, 0, or +1). + +=item * the Cleg operator (less than, equal, or greater) is defined +in terms of Ccmp, so C$a leg $b is now defined as C~$a cmp ~$b. +The sort operator still defaults to Ccmp rather than Cleg. The +C = operator's semantics are unchanged except that it returns +and Order value as described above. 1. I suggest for parity (vs leg as exists eq vs ==) and clarity that you explicitly state the = semantics like you did for leg, rather than just saying it was unchanged. Eg, amend the last sentence there to say specifically that C$a = $b is now defined as C+$a cmp +$b, especially since you don't explicitly say this anywhere else in Synopsis 3. +[Conjecture: we could probably do away with C!~, but probably not +C!= or Cne.] 2. I support eliminating !~ in favor of just !~~. Unlike != or 'ne', which are each part of a set of 6 operators that remained unchanged as a whole from Perl 5 (so backwards compatability could be useful), the binding/smartmatch operator set that !~ belongs to was greatly changed, so there is no benefit to keeping !~ just because that syntax was in Perl 5. 3. The Precedence table at the end of Synopsis 3 currently does not reflect your latest changes. Most importantly, it is missing 'eqv' and 'leg'. Also importantly, it is missing the ?| operator and friends, which in my case leads to confusion as to whether it belongs with the tight-or set or the bitwise operator set. Less importantly, I would consider the main versions of the negated eqality operators !==, !eq, !~~ to be more important than the alternate != or ne forms; as it is, that table already just lists the more canonical versions of things like the zip operator rather than both or the alternate versions. 4. I'm confused regarding the ?| operator, which is only mentioned in this paragraph near the top of Synopsis 3: =item * Bitwise operators get a data type prefix: C+, C~, or C?. For example, C| becomes either C+| or C~| or C?|, depending on whether the operands are to be treated as numbers, strings, or boolean values. Left shift C becomes C + , and correspondingly with right shift. Unary C~ becomes either C+^ or C~^ or C?^, since a bitwise NOT is like an exclusive-or against solid ones. Note that C?^ is functionally identical to C!. C?| differs from C|| in that C?| always returns a standard boolean value (either 1 or 0), whereas C|| return the actual value of the first of its arguments that is true. First of all, this paragraph seems to confuse in my mind as to whether or not ?| is a bitwise operator. On one hand, it says that it takes 2 boolean values as input and or's them. On the other hand, it says that it is just like ||, which takes any kind of values as input, but that the latter returns the first actual value of the first 2 arguments, while the former doesn't. The || comparison suggests that maybe ?| belongs with the tight-or operator set rather than bitwise. It might help if some of this was clarified. Part of the confusion though is that ?| isn't in the operator precedence table. -- Darren Duncan