Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On 8/14/06, Smylers wrote: David Green writes: Thanks for that. In summary, if I've understood you correctly, it's that: =:= two aliases to the same actual variable === one variable contains a copy of the other's actual contents eqv both contain contents which represent the same thing but may have come from different sources And that being true at one level implies being true for the above levels. Yes? Right. (Where the ordering for "above" means =:= implies ===, and === implies eqv, but not in the other direction, of course.) > === Example: Suppose I have some employee objects, and I employ two John Smiths. They have the same name, work in the same department, and by stunning coincidence everything my class knows about them just happens to be the same. Except that they wouldn't. Because each one would have a separate payroll number, or some artificial thing invented just for the sake of being different. So this example doesn't sound plausible to me. Well, I didn't say it was a *good* payroll system! OK, it's a silly contrived example; maybe my objects should have represented the reticulated flanges I have in stock, since one piece of inventory is the same as any other. Except I wouldn't really create an object for each one, I'd just have a single group-object that contained a $num_available counter (Anyone cleverer than I should feel free to jump in with a better example.) So I now understand what this operator does. But I'm still struggling to fathom where I would ever have a use for it. Maybe you wouldn't -- eqv is what most of us will use most of the time, I expect (being the ordinary everyday parallel to == and eq). But since it is possible to use variables both by value and by reference, there still needs to be a way to work with and compare both of them when you want to do fancy advanced stuff. -David
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
David Green schreef: > === > ...is equality-of-contents, basically meaning that the things you're > comparing contain the same [...] values. How about strings; are normalized copies used with the === ? http://www.unicode.org/faq/normalization.html http://www.unicode.org/notes/tn5/ -- Affijn, Ruud "Gewoon is een tijger."
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
David Green writes: > On 8/13/06, Smylers wrote: > > > Please could the proponets of the various behaviours being discussed > > here share a few more concrete examples ... > > OK, Thanks for that. In summary, if I've understood you correctly, it's that: =:= two aliases to the same actual variable === one variable contains a copy of the other's actual contents eqv both contain contents which represent the same thing but may have come from different sources And that being true at one level implies being true for the above levels. Yes? > === > Example: Suppose I have some employee objects, and I employ two John > Smiths. They have the same name, work in the same department, and by > stunning coincidence everything my class knows about them just > happens to be the same. Except that they wouldn't. Because each one would have a separate payroll number, or some artificial thing invented just for the sake of being different. So this example doesn't sound plausible to me. > But they're still different objects (the payroll system definitely > needs to produce two cheques, although since they earn the same > salary, it doesn't matter which one of them gets which cheque); so > $john1 !=== $john2, and I can tell them apart. And why on earth would you be making such a comparison? If you have a list of employees who need cheques then you just iterate through them and process them in turn; you wouldn't be comparing an arbitrary pair of them. So I now understand what this operator does. But I'm still struggling to fathom where I would ever have a use for it. Smylers
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
David Green writes: > I guess my problem is that [1,2] *feels* like it should === [1,2]. > You can explain that there's this mutable object stuff going on, and I > can follow that (sort of...), but it seems like an implementation > detail leaking out. The currently defined behaviour seems intuitive to me, from a starting point of Perl 5. The difference between: my $new = [EMAIL PROTECTED]; and: my $new = [EMAIL PROTECTED]; is that the second one is a copy; square brackets always create a new anonymous array rather than merely refering to an existing one, and that's the same thing that's happening here. Think of square brackets as meaning something like Array->new and each one is obviously distinct. > And I feel this way because [1,2] looks like it should be platonically > unique. I'd say that C< (1, 2) > looks like that. But C< [1, 2] > looks like it's its own thing that won't be equal to another one. Smylers
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
Way back on 7/14/06, Larry Wall wrote: On Thu, Jul 13, 2006 at 10:19:24PM -0600, David Green wrote: [...] 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. Yup, which it would have to be even given the slightly-off way I was thinking of it. So I've quietly snipped the part where I said it wasn't and will pretend it was never there. : (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 platonic heaven, I'm just : mentioning it directly instead of dropping a name.) On the contrary, there isn't one single platonic [1,2], since square brackets construct a mutable Array object: @a := [1,2]; @b := [1,2]; @b[0]++; say "@a @b"; # 1 2 2 2 $ perl -e 'print ++([1,2]->[1])' 3 Hmm... well, I guess I shouldn't be surprised that that worked, it makes sense -- you can't have an array-ref unless it refers to something. But something still bothers me... Perl knows that my anonymous array-ref is pointing at something, so it's [effectively] got some kind of "internal" name that it knows about, but I don't. So it isn't really anonymous... it's a Rumpelstiltskin array! I guess my problem is that [1,2] *feels* like it should === [1,2]. You can explain that there's this mutable object stuff going on, and I can follow that (sort of...), but it seems like an implementation detail leaking out. In many languages, strings are just character arrays, and presumably someone could write a version of Perl that actually built strings out of array refs, but I'd still want "foo" to === "foo". And I feel this way because [1,2] looks like it should be platonically unique. Or at least leibnizianly unique: if two things don't have any different features, then they aren't different. And one [1,2] can do anything that another [1,2] can. ...Except have the same object ID, which doesn't seem particularly useful, except for distinguishing them, which is what I don't want to do. Is there a useful non-implementary reason to tell them apart (excepting obfuscated P6 and stuff Damian might do), or can you just hide it?? (Ignorance is bliss for bears of little brain like me.) Some convenient skidding around to make identical array-refs look, well, the identical. Of course, when you suppress one thing, you have to start stomping down spots all over the waterbed, and eventually it might burst. Maybe I'm just not thinking about it from the right direction... Do I feel that \1 (a ref to a literal "1") should be platonic? Does it matter? As you said, ordinarily I'll be assigning rather than binding, so stuff will just work. Can I make a nested Seq with something like (1;2; 3,4)? Compared to the nested Array referential [1,2, [3,4]]? [EMAIL PROTECTED] should be different from (!===) [EMAIL PROTECTED] because even if @a eqv @b eqv (1,2), @b might change. But if $a=[1,2] and $b=[1,2] there's nothing I can change that will make $a and $b different, so for $a not to === $b is Fairly Surprising in Principle. That is, nothing *else* I can change, since of course changing either $a or $b will make them different. You may tell me that $b[0]++ *is* changing something other than $b, but it sure looks like changing $b. The only way I can get at the original [1,2] is by going through $b, so I think I am changing $b. But wouldn't I think the same thing if [EMAIL PROTECTED] and I do $b[0]++? It might look superficially as though I were changing $b, but $b still is [EMAIL PROTECTED] -- @b is what's really changed. Hmmm. If Perl is simply more complex, there's no point my trying to hold a naive view. Maybe it's one of those things that never will seem quite comfortable until I just get used to it -David
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On 8/13/06, Smylers wrote: 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)? OK, if I can come up with examples that make sense, then that probably means I actually understand it myself! eqv ...is your standard equality-of-values, which would be just = or == in many languages, and which Perl has never really had. == and eq coerce their operands to be numbers or strings, which was fine back in days or yore when Perl only had nums and strings. With the introduction of references/objects, Perl effectively got user-definable types without a user-definable equality operator, so you either had to rely on suitable numifications (or stringifications) of your objects to make sense, or overload stuff, or something. In P6 you can just compare their values in a "normal" way (or still numify/stringify them using == or eq if that's what you want). Example: I have a Date class that lets each of its objects carry around its own different epoch value, so using == won't work (unless both dates that I'm comparing happen to share the same epoch -- a yucky work-around might be "if $a==$b && $a.epoch==$b.epoch"). And let's suppose my Dates are text-insensitive-but-preserving, meaning that objects created as "2006/1/1" and as "Jan. 1, 2006" return those exact strings when stringified, even though they represent the same date: so comparing with eq won't work either. Instead I want to compare my dates with eqv which compares their "real" values. ("Real" is determined by the class -- this is where the Special Key ID stuff comes in. In this example, the SKID for a date might be an int using a fixed epoch; or it might be a text representation in canonical form. The user doesn't have to care, of course.) (eqv also means you no longer need code like "if (we're using ints) return $a==$b else if (we've got strings) return $a eq $b", which was occasionally a pain even in those Days of Yore. Now that P6 can use variable types, you don't [necessarily] need to specify the type in the equality operator, you can just use eqv to do the appropriate kind of comparison. (And "cmp" is becoming the analogue of "eqv" instead of "eq".)) === ...is equality-of-contents, basically meaning that the things you're comparing contain the same variables and values. (E.g. things that are references to other variables, possibly nested in some kind of data structure.) Now if you have a couple of plain old ints, then it's the same as testing whether they have the same values ("eqv"). But if $a contains a ref to @x and $b contains a ref to @y, then $a will not === $b. (Unless @x and @y are really the same variable in disguise, of course. $a might *eqv* $b, because @x and @y could have the same value, but as long as $x and $y are different guys, then $a !=== $b. Conversely, if $a does === $b, then they must have the same value too, i.e. it follows that $a eqv $b.) Example: Suppose I have some employee objects, and I employ two John Smiths. They have the same name, work in the same department, and by stunning coincidence everything my class knows about them just happens to be the same. So they're basically indistinguishable (serialising one John Smith object produces the same results as the other -- and indeed, $john1 eqv $john2). But they're still different objects (the payroll system definitely needs to produce two cheques, although since they earn the same salary, it doesn't matter which one of them gets which cheque); so $john1 !=== $john2, and I can tell them apart. In fact, === is how a hash tests its keys (assuming it's a hash that uses objects rather than a P5-like hash that uses stringy keys -- of course, for a string hash, === wouldn't work out any different from eqv anyway). =:= ...is equality-of-variable, or binding -- it simply checks whether its operands are both the same variable (possibly under different names). This might be a little esoteric for "ordinary" code (if there is any such thing), but binding is pretty common in P6, even if inconspicuous: sub foo($a, $b) will bind $x to both $a and $b if I call foo($x, $x). I might want to know whether my $a and $b really are the same variable passed in twice or not. Example: a fairly simple reason why you might care whether you've got the same variable twice is if you're doing some expensive comparison -- an easy optimisation is to check whether the two things you're comparing are really the same thing to start with. (Or, going back to my double John Smiths setup, my payroll functions can make sure that all the John Smith really are different peopl
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On July 14th Yuval Kogman wrote: > 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. Hi there. Ann's (excellent, very useful, and much appreciated) summary reminded me that this was still pending. Did you catch your flight? For the benefit of anybody else who's struggling to remember a thread from a month ago this was my original request. 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)? Cheers. Smylers
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=; : @y=; : : $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,
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
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 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
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 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: ===, =:=, ~~, 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
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 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
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
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: ===, =:=, ~~, 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
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: ===, =:=, ~~, 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: ===, =:=, ~~, 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: ===, =:=, ~~, 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
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
At 10:36 PM -0700 7/13/06, 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. 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. -- Darren Duncan
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
Yuval Kogman wrote: Jonathan Lang wrote: > Apparently, there are _four_ basic kinds of comparison: the ones > mentioned above, and == (I believe that eq works enough like == that > whatever can be said about one in relation to ===, =:=, or eqv can be > said about the other). I'd be quite interested in an expansion of > David's example to demonstrate how == differs from the others. sub &infix:<==> ( Any $x, Any $y ) { +$x === +$y; # propagate coercion failure warnings to caller } sub &infix: ( Any $x, Any $y ) { ~$x === ~$y } So the purpose of === is to provide a means of comparison that doesn't implicitly coerce its arguments to a particular type? -- Jonathan "Dataweaver" Lang
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On Thu, Jul 13, 2006 at 21:55:15 -0700, Jonathan Lang wrote: > Apparently, there are _four_ basic kinds of comparison: the ones > mentioned above, and == (I believe that eq works enough like == that > whatever can be said about one in relation to ===, =:=, or eqv can be > said about the other). I'd be quite interested in an expansion of > David's example to demonstrate how == differs from the others. sub &infix:<==> ( Any $x, Any $y ) { +$x === +$y; # propagate coercion failure warnings to caller } sub &infix: ( Any $x, Any $y ) { ~$x === ~$y } -- Yuval Kogman <[EMAIL PROTECTED]> http://nothingmuch.woobling.org 0xEBD27418 pgp3B4GnByYFK.pgp Description: PGP signature
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On Thu, Jul 13, 2006 at 12:50:19 -0700, Larry Wall wrote: > On Thu, Jul 13, 2006 at 09:32:08PM +0300, Yuval Kogman wrote: > : [1] My preferred ergonomics: > : > : 1. eqv goes away > : 2. what was eqv is renamed to === > : 3. === becomes =:=, which has a "constant" feel to it > : 4. =:= is rarely useful IMHO, so you can just type > : variable($x) =:= variable($y) > > It is important for eqv to be alphabetic so we can have the functional > form take an optional signature parameter to specify what is compared. There's no contradiction, === could be an alias to eqv ;-) -- Yuval Kogman <[EMAIL PROTECTED]> http://nothingmuch.woobling.org 0xEBD27418 pgpPDRBxXCeip.pgp Description: PGP signature
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
David Green wrote: 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 : !)) Agreed. 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. Apparently, there are _four_ basic kinds of comparison: the ones mentioned above, and == (I believe that eq works enough like == that whatever can be said about one in relation to ===, =:=, or eqv can be said about the other). I'd be quite interested in an expansion of David's example to demonstrate how == differs from the others. -- Jonathan "Dataweaver" Lang
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
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. (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.) Examples: @x=; @y=; $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 (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. 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? (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 platonic heaven, I'm just mentioning it directly instead of dropping a name.) -David
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
At 5:36 PM +0300 7/13/06, Yuval Kogman wrote: > User defined types can choose on their own whether to override === and/or .id or not, and they would use their own knowledge of their internal structures to do an appropriate deep comparison. There is no need to try to generate some kind of unique numerical .id for arbitrarily complex objects. That creates a mess - sometimes objects compare themselves based on their value, and sometimes based on their containing slot. These are very different semantics. The idea here is that === is a test for deep-as-possible immutable equality. If the user-defined object is immutable, then === does a full deep compare. If the object is mutable, then === goes only as deep as can be guaranteed will never change, which is usually what =:= looks at and no further. There is no mess at all, the comparing by value is related to the immutability, and all objects of the same class would be the same in that respect. Incidentally, your Currency example would likely be an immutable type. -- Darren Duncan
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On Thu, Jul 13, 2006 at 12:50:19PM -0700, Larry Wall wrote: : Then $a eqv $b and $a leg $b both just default to a signature that selects : everything. Though arguably P5's string-forcing semantics should be C and the polymorphic semantics should probably be C. Larry
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
On Thu, Jul 13, 2006 at 09:32:08PM +0300, Yuval Kogman wrote: : [1] My preferred ergonomics: : : 1. eqv goes away : 2. what was eqv is renamed to === : 3. === becomes =:=, which has a "constant" feel to it : 4. =:= is rarely useful IMHO, so you can just type : variable($x) =:= variable($y) It is important for eqv to be alphabetic so we can have the functional form take an optional signature parameter to specify what is compared. eqv($a,$b, :($x,$y)) Think of this as the same as the sort specifier that says what to sort on, only we're only interested in eqv-ness rather than cmp-ness. In fact, cmp (or something like it) also wants to take a third parameter: leg($a,$b, :($x is num,$y is rev)); and then sort is just done with the same signature: sort :($x is num,$y is rev), @foo; or some such, however you want to canonicalize the records. The sort routine can decide whether it'll be more efficient to do various transforms or maneuvers based on the declarative syntax of the signature. Then $a eqv $b and $a leg $b both just default to a signature that selects everything. Larry
Re: ===, =:=, ~~, eq and == revisited (blame ajs!) -- Explained
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. Then again, I trust that Larry's opinion is probably better and at the very least more likely to be accepted than mine ;-) [1] So, this is the deal: === is for checking immutable equality. This is a bit nasty to explain. eqv is going to be deep comparison, like most of us thought '===' was going to be (I had initially thought that eqv was renamed to === when === started popping up). =:= is something completely different, but will be easy to explain in a moment. What it means for something to be immutable can be demonstrated rather easily here: my $x = 10; my $y = $x; $x === $y; # true $y++: $x === $y; # false Since numbers (and also strings) are "simple" values, that are not modified in place (at least not explicitly), but are instead copied and modified or just replaced when you change them, the .id of the thing inside $x and $y is bound to the value. You could rationalize this such that .id is the same if and only if it doesn't actually matter (and never will matter) if the value is in the same chunk of memory or a separate one, as far as the runtime is concerned. Arrays and hashes, and other complex types can, on the other hand have parts of them transformed without first cloning everything (which is precisely why they're useful). The underlying idea is that === can be used to test if two values are *always* going to be the same (if they're container gets a different value in it that does not mean that they are no longer the same). eqv, on the other hand is used to test whether or not two values are the same right now, without making any implications as to what their values will be later on, since they may mutate. This is deceivingly like == and eq if you assume that numbers and strings are changed, instead of replaced. Lastly, =:= is really variable($x) === variable($y) - that is, whether or not the container is the same value or not. This basically checks whether either $x or $y was at some point bound to the other, or in specific situations whether they're tied to the same representation even if they are different containers. Overridding .id is useful for when you want to imply that two items are exactly the same and will always be the same and will never change as far as their comparison is concerned (both eqv and === will always be true), even if the default implementation of === does not return true due to technical details. === can be thought of as .id eqv .id. I hope this clears things up, and thanks again, Larry and Audrey, for clearing this up. I'd like for someone with better english skills to summarize into an S03 patch please. It needs to be much shorter =) [1] My preferred ergonomics: 1. eqv goes away 2. what was eqv is renamed to === 3. === becomes =:=, which has a "constant" feel to it 4. =:= is rarely useful IMHO, so you can just type variable($x) =:= variable($y) Ciao -- Yuval Kogman <[EMAIL PROTECTED]> http://nothingmuch.woobling.org 0xEBD27418 pgpU0Qe5CPlhQ.pgp Description: PGP signature
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
On Thu, Jul 13, 2006 at 00:55:30 -0700, Darren Duncan wrote: > So, in the general case, it would seem best if the binary operator === was > just an ordinary method that each class provides, rather than requiring > classes to defined a .id. Or > in addition to this to help with performance, a .id can exist anyway that > optionally returns an appropriate hash of an object. But what is the benefit here? Keying by object is a difficult topic. In Perl 5 you sometimes want to key by refaddr (more often than not) because you are associating new metadata with the instance, that does not belong inside the instance. On the other hand you also often want something like "$obj" to be the key, if it can properly stringify, so that an object like a currency: my $x = Currency.new( code => "USD" ); my $y = Currency.new( code => "USD" ); $hash{$x} = 1; say $hash{$y}; # 1 will DWIM. But this really depends on both the item being used, *and* the way it is being used. So I can see the value of making the second type of keying possible and easy with an .id method (which at the very lowest level can probably just emit e.g. a YAML representation of an object to ensure uniqueness, if performance is *really* not an issue). But this does not relate to equality, it's only useful for defining it. We were essentially questioning the reason === is specced to behave as it currently does, because we feel that it's not very useful if it's not clear cut that it should either *really* compare, or not compare at all. And if it doesn't compare, we'd like a deep comparison operator in S03. > Built-in mutable types, like Array or Hash, would not override the > Object-defined ===, which is equivalent to =:=, nor the built-in .id, which > returns the object itself. This > is reasonable in practice because the contents of those containers could be > changed at any time, especially if the containers are aliased to multiple > variables that are outside > of the testing code's control. The only thing that can be guaranteed to be > constant over time is that whether or not an object is itself, as determined > by =:=. By contrast, if > === were to do a deep copy with mutable types, the results could not be > trusted to be repeatable because the moment after === returns, the > container's value may have changed > again, so actions done based on the === return value would be invalid if they > assumed the value to still be the same at that time, such as if the mutable > type was used as a hash > key and was to be retrievable by its value. The behavior for arrays is useless to me, because I already have =:=. I can write a hybrid ===/=:= operator for very special cases, but 99% of the time I want to ask "do these (arrays|hashes) contain the same values *right now*?" > User defined types can choose on their own whether to override === and/or .id > or not, and they would use their own knowledge of their internal structures > to do an appropriate > deep comparison. There is no need to try to generate some kind of unique > numerical .id for arbitrarily complex objects. That creates a mess - sometimes objects compare themselves based on their value, and sometimes based on their containing slot. These are very different semantics. -- Yuval Kogman <[EMAIL PROTECTED]> http://nothingmuch.woobling.org 0xEBD27418 pgpxFsetaGrOi.pgp Description: PGP signature
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
At 7:25 PM +0300 7/12/06, Yuval Kogman wrote: Over at #perl6 we had a short discussion on =:=, ===, and ~~, mostly raised by ajs's discussion on Str items and ===. Coincidentally, I raised almost the same questions there a week earlier, and had a brief discussion with audreyt about it, though the answers that came out of it seemed rather different than what was in this thread so far, so I will share them. See the following url: http://colabti.de/irclogger/irclogger_log/perl6?date=2006-07-06,Thu&sel=376#l599 I will also quote the text as it was short, snipping out unrelated parts: [ 11:29pm ] dduncan : slight change of topic, but I was wondering how .id works with non-trivial types [ 11:29pm ] dduncan : eg, what does the .id of a Pair look like? [ 11:29pm ] dduncan : I know that to users it shouldn't matter, but to people implementing composite types, it does [ 11:30pm ] audreyt : dduncan: one possibility - could be just itself. [ 11:33pm ] dduncan : one key thing I'm wondering about .id for immutable types is ... are they supposed to generate some neutral value like an integer, two of which can then be compared independently of the type definition, or will they contain references to the actual object all the time and that the object's class still needs to declare a === method which is invoked as needed? [ 11:33pm ] dduncan : if it is the latter, I imagine that implementation will be simpler, at a possible cost of performance if the same comparison is done a lot [ 11:34pm ] audreyt : dduncan: the latter [ 11:34pm ] dduncan : okay, that answers my question So, in the general case, it would seem best if the binary operator === was just an ordinary method that each class provides, rather than requiring classes to defined a .id. Or in addition to this to help with performance, a .id can exist anyway that optionally returns an appropriate hash of an object. A default === would be defined in Object, which returns the same result as =:= returns; two objects are equivalent iff they are the same container. A default .id defined in Object would simply return the same object it was invoked on. Built-in immutable types, like Str and Int and Pair and Seq, would override that === such that they return true iff the two operands are containers of the same class and the two containers both hold appearances of the same (universally distinct) value. This is determined by doing a deep comparison of the values themselves, as is appropriate. (Internally to the type's implementation, a domain-appropriate hash of the value could optionally be generated at an appropriate time and be used to speed up === operations, with appropriate action taken if it isn't guaranteed that multiple distinct values won't become identical hash values.) The .id could be overridden to return a simple number or string or binary for simpler types, and return the object itself otherwise. Built-in mutable types, like Array or Hash, would not override the Object-defined ===, which is equivalent to =:=, nor the built-in .id, which returns the object itself. This is reasonable in practice because the contents of those containers could be changed at any time, especially if the containers are aliased to multiple variables that are outside of the testing code's control. The only thing that can be guaranteed to be constant over time is that whether or not an object is itself, as determined by =:=. By contrast, if === were to do a deep copy with mutable types, the results could not be trusted to be repeatable because the moment after === returns, the container's value may have changed again, so actions done based on the === return value would be invalid if they assumed the value to still be the same at that time, such as if the mutable type was used as a hash key and was to be retrievable by its value. User defined types can choose on their own whether to override === and/or .id or not, and they would use their own knowledge of their internal structures to do an appropriate deep comparison. There is no need to try to generate some kind of unique numerical .id for arbitrarily complex objects. One thing that can't be overridden is that === can only return true iff both operands are of the same class. This includes undef, as each class has its own undef that is distinct from those of other classes. So if this is the way that things worked, then it would be very easy to implement it for any kind of type. And it would be very reliable to use any type as a hash key. Note that, while the fact may be determinable by some other means, it may be useful to have an explicit meta-method for all types that says whether the type is immutable or mutable. A user defined type saying that it is immutable is making a promise to the compiler that its objects won't change after they are created. As for being able to tersely do deep comparisons of mutable types, I don't think that === is ap
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
Yuval Kogman wrote: On Wed, Jul 12, 2006 at 17:58:03 -0400, Aaron Sherman wrote: Then ~~ is wrong in that respect, and I think we should be talking about that, not about making === into "~~, but without invoking code when it shouldn't." But it should! It's the smart match! If the rhs matches the code ref (the code ref gets it as an argument it's a match! That's why ~~ isn't a comparison operator, but a smart match operator - it DWIMs *very* deeply DWIM generally means "don't shoot me in the head for trying this", and it can be strongly argued that C is almost certain to shoot you in the head a couple of times in your P6 career if we don't fix it. Now, I'm all for every single case that Larry put in the table for Smart Matching in S03... EXCEPT FOR RUNTIME DISPATCH! There are only two cases of runtime dispatch in there that you could possibly invoke: Array/Array and Any/Any. Fix those two, and I think ~~ DWIMs safely and just as powerfully (perhaps much more so). My suggestion (falling back to a much simpler and less dynamic =~= for runtime dispatch) is one way to fix them, and I think that if we DO fix them in that manner, then no one's expectations will be violated (unless you expected C<@a1 ~~ @a2> to be shorthand for a function vector, dot-product-like, parallel dispatch, in which case I'm going to make the suggestion that you quietly retire from public life and find a nice place in the mountains. ;-) Really, all of the magic on ~~ isn't intended for such runtime traversal of containers. it's intended for the immediate semantic value of the compile-time typed match, most notably in the case of given which has more connotations to hang semantic meaning off of in English. To invoke those special rules when recursively evaluating the "sameness" of containers doesn't even make sense if you stop and consider why you would do such a comparison. Why is C<$a ~~ $b> going to invoke code when I know nothing about $a and $b at compile time? Is that useful other than in defining an alias for ~~?
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
On Wed, Jul 12, 2006 at 16:16:13 -0400, Aaron Sherman wrote: > The other way to think about === would be that it tells you if its LHS > *could* be constant-folded onto its RHS (if it were constant for long > enough) What is the benefit here? > Because of the word "deep". Deep implies arbitrary work, which isn't > really what you want in such a low-level operator. However, using these > operator, one could easily build whatever you like. The number of times i *sigh*ed at having to reinvent deep operators in a clunky way in Perl 5 is really not in line with Perlishness and DWIM. Also ~~ is deep in exactly the same way. Perl is also not low level. I could build it, and I have, but I don't want to. It can short circuit and be faster when the structure is definitely not the same (totally different early on) or definitely the same (refaddr is equal, etc). Should I go on? > I'd avoid saying "memory", here. Some implementations of Perl 6 might > not know what memory looks like (on a sufficiently abstract VM). "Slot" -- Yuval Kogman <[EMAIL PROTECTED]> http://nothingmuch.woobling.org 0xEBD27418 pgpvVdjsJ0Et9.pgp Description: PGP signature
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
On Wed, Jul 12, 2006 at 17:58:03 -0400, Aaron Sherman wrote: > Then ~~ is wrong in that respect, and I think we should be talking about > that, not about making === into "~~, but without invoking code when it > shouldn't." But it should! It's the smart match! If the rhs matches the code ref (the code ref gets it as an argument it's a match! That's why ~~ isn't a comparison operator, but a smart match operator - it DWIMs *very* deeply. -- Yuval Kogman <[EMAIL PROTECTED]> http://nothingmuch.woobling.org 0xEBD27418 pgpyx4u1552HO.pgp Description: PGP signature
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
On Wed, Jul 12, 2006 at 16:16:13 -0400, Aaron Sherman wrote: > Isn't that ~~? > > Per S03: > > Array Array arrays are comparablematch if $_ »~~« $x > > ~~ is really the all-purpose, bake-your-bread, clean-your-floors, > wax-your-cat operator that you're looking for. Not at all, because: ( [ 1, 2 ], 3 ) ~~ ( { 1 }, { 1 } ) It's matching, not equality. > which is true. Ain't recursive hyperoperators grand? It isn't a hyperoperator, it's just recursive ;-) > > 2. is .id *always* a low level type representation of the object's value? > > It's > > specced that low level typed items have the same ID when they have the same > > value. What about complex types? > > It cannot be for complex types or even strings... well, at least it > I not be I we care about performance That's orthogonal. .id is used for hash keys. If you're keying y hubble images then they must be unique for some keyspace, and that's where .id makes a mapping. > =:= looks in the "symbol table" (caveat dragons) to see if LHS > refers to the same variable as the RHS. Does this dereference? > Probably not, but I'm not sure, based on S03. Then it's a purely lexical opeation, and it doesn't even work for my $x := $array[3]; $x =:= $array[3]; but i'll pretend you didn't say that ;-) -- Yuval Kogman <[EMAIL PROTECTED]> http://nothingmuch.woobling.org 0xEBD27418 pgpPMmzta8SWk.pgp Description: PGP signature
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
On Wed, 2006-07-12 at 15:32 -0500, Jonathan Scott Duff wrote: > On Wed, Jul 12, 2006 at 04:16:13PM -0400, Aaron Sherman wrote: > > On Wed, 2006-07-12 at 19:25 +0300, Yuval Kogman wrote: > > > 4. will we have a deep (possibly optimized[1]) equality operator, that > > > *will* return true for @foo = ( [ 1, 2 ], 3 ); @bar = ( [ 1, 2 ], 3 ); > > > op(@foo, @bar)? > > > Is it going to be easy to make the newbies use that when they mean "it's > > > the > > > same", like they currently expect == and eq to work on "simple" values? > > > > Isn't that ~~? [...] # hmm, what kind of reduction IS that? ;) > > ~~ is really the all-purpose, bake-your-bread, clean-your-floors, > > wax-your-cat operator that you're looking for. > > Granted, ~~ will return true in that case. I think the main problem > is Yuval wants a guarantee that it will return true if and only if > the things on either side have the same deep structure and values. > > Currently, ~~ will also return true for structures where this does > not hold. For example: > > @a = ( [ 1, 2] , 3 ); > @b = ( sub { return 1 }, sub { return 1 } ); > @a ~~ @b; # true Then ~~ is wrong in that respect, and I think we should be talking about that, not about making === into "~~, but without invoking code when it shouldn't." > Why is that true? By the rules of hyper-operation, it turns into > this: > > [1,2] ~~ sub { return 1 } > 3 ~~ sub { return 1 } > > which is true if these return true values: > > sub { return 1 }->([1,2]) > sub { return 1 }->(3) OK, so this always bothered me, I just wasn't sure why. Now I know, and I think I agree with Yuval quite a bit more. ~~ should never imply running it's data arguments as code *when dispatched at runtime*. It's: * likely to cause security problems when I accidentally compare a safe, internal structure that (probably unknown to me) contains code against an unsafe, external structure that I got from a user. * potentially a destructive comparison. * potentially not hyper-parallelization friendly * probably bad in other ways I could think of, given time. Let me boil that down to a simple assertion: comparison via ~~ which will have to perform run-time dispatch should never I to have side-effects (dynamic language, caveat, caveat...) So, I do agree that we need a new operator, but I disagree about how it should be used. I'd suggest: C<=~=> This is similar to C<~~> for arguments that are simple value types such as C or C. For objects which do not have a C<=~=> operation, C<===> is invoked. By default, the only objects which will define a C<=~=> operation will be containers, which will look like: our Bool multi submethod infix:<=~=> ($a: Container $b) { [&&] $a >>=~=<< $b; } which works for Hashes too, since a Pair is a container, so we'll just recursively hyperoperate through each of the hash's .kv Pairs, comparing them, though it might have to sort the Pairs by keys in order to assure it's comparing apples to apples. That's it. Just three types of behavior, unlike ~~s massive table of behavior. Then, in the table for C<~~>: $_ $xType of Match ImpliedMatching Code == = == ... Array Array arrays are comparablematch if $_ »=~=« $x ... Any Any run-time dispatchmatch if infix:<=~=>($_, $x) The first change is to Array/Array, and this is to minimize surprises when comparing containers. There might be a special case for containers that have typed buckets, but I'm not even going to touch that right now. The second change is to Any/Any, and that's purely a matter of putting the control in the hands of the caller, not whoever constructed the caller's data. Anything else is a debugging nightmare. In general, I would expect that no one would use =~= directly (hence the ugly, name that's longer than ~~), it's just an implementation detail of run-time dispatch on ~~ Thoughts? -- Aaron Sherman <[EMAIL PROTECTED]> Senior Systems Engineer and Toolsmith "We had some good machines, but they don't work no more." -Shriekback
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
On Wed, Jul 12, 2006 at 04:16:13PM -0400, Aaron Sherman wrote: > On Wed, 2006-07-12 at 19:25 +0300, Yuval Kogman wrote: > > 4. will we have a deep (possibly optimized[1]) equality operator, that > > *will* return true for @foo = ( [ 1, 2 ], 3 ); @bar = ( [ 1, 2 ], 3 ); > > op(@foo, @bar)? > > Is it going to be easy to make the newbies use that when they mean "it's the > > same", like they currently expect == and eq to work on "simple" values? > > Isn't that ~~? > > Per S03: > > Array Array arrays are comparablematch if $_ »~~« $x > > ~~ is really the all-purpose, bake-your-bread, clean-your-floors, > wax-your-cat operator that you're looking for. Granted, ~~ will return true in that case. I think the main problem is Yuval wants a guarantee that it will return true if and only if the things on either side have the same deep structure and values. Currently, ~~ will also return true for structures where this does not hold. For example: @a = ( [ 1, 2] , 3 ); @b = ( sub { return 1 }, sub { return 1 } ); @a ~~ @b; # true Why is that true? By the rules of hyper-operation, it turns into this: [1,2] ~~ sub { return 1 } 3 ~~ sub { return 1 } which is true if these return true values: sub { return 1 }->([1,2]) sub { return 1 }->(3) Which they do. So, smart-match fails as a "deep equality" operator precisely because it's so smart. -Scott -- Jonathan Scott Duff [EMAIL PROTECTED]
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
On Wed, 2006-07-12 at 19:25 +0300, Yuval Kogman wrote: > Over at #perl6 we had a short discussion on =:=, ===, and ~~, mostly raised by > ajs's discussion on Str items and ===. *wave* > 1. what is .id on references? Is it related to the memory slot, like refaddr() > in Perl 5? That's something I'm not sure of, so I'll let it go, other than to say that that question should probably avoid the word "memory", see below. 4. will we have a deep (possibly optimized[1]) equality operator, that *will* Now, let me handle this one out of order, since I think it's really key: > return true for @foo = ( [ 1, 2 ], 3 ); @bar = ( [ 1, 2 ], 3 ); op(@foo, > @bar)? > Is it going to be easy to make the newbies use that when they mean "it's the > same", like they currently expect == and eq to work on "simple" values? Isn't that ~~? Per S03: Array Array arrays are comparablematch if $_ »~~« $x ~~ is really the all-purpose, bake-your-bread, clean-your-floors, wax-your-cat operator that you're looking for. It sounds like pugs is wrong here WRT the spec, since: ( [ 1, 2 ], 3 ) ~~ ( [ 1, 2 ], 3 ) is the same as: [1,2]~~[1,2] && 3 ~~ 3 which is the same as: (1~~1 && 2~~2) && 3~~3 which is true. Ain't recursive hyperoperators grand? Of course, I'm assuming that a comparison hyperoperator in boolean context returns the [&&] reduction of all of the values... that's an interesting assumption, isn't it? But, it seems to be the assumption made by S03 under Smart Matching, so I say it's true. ;) > 2. is .id *always* a low level type representation of the object's value? It's > specced that low level typed items have the same ID when they have the same > value. What about complex types? It cannot be for complex types or even strings... well, at least it I not be I we care about performance. That is, if C<$anything.id> needs to read every byte of $anything, then an anything that happened to be a Buf containing the 3GB in-memory raw image from the Hubble is going to really make C<.id> unhappy. I would hope that C<.id> is an efficient enough operation that === should not look like a performance bottleneck in my code > 3. Are these descriptions of the operators correct? > > ~~ matches the left side to a description on the right side > =:= makes sure the objects are actually the same single object (if $x > =:= $y > and you change $x. then $y. was also changed... is > this .id on refs?) Is =:= really eq .id? or more like > variable($x).id eq variable($y).id? > === makes sure that the values are equivalent ( @foo = ( 1, 2, 3 ); > @bar = ( 1, > 2, 3); @foo === @bar currently works like that, but @foo = ( [ 1, 2 ], > 3 ); > @bar = ( [ 1, 2 ], 3 ); @foo === @bar does not (in pugs). This is not > useful > because we already have this return false with =:=). Let me counter-propose a slightly different way of saying that: ~~ as above. I think we all agree on this. =:= looks in the "symbol table" (caveat dragons) to see if LHS refers to the same variable as the RHS. Does this dereference? Probably not, but I'm not sure, based on S03. === Compares types and .id values. An implementation of this, as I interpreted S03, and with some assumptions made, and with some extra bits filling in the cracks where S03 didn't quite specify an implementation: * A .id method may return C, C or C. === returns false for two objects which are not the same type (with the same traits), and thus the comparison must always be between identical .id return types. * As a special case, however, all "undefined" values (not objects which have the undefined trait, but true undefs with no other functionality) are === to each other. * Objects are always compared according to their underlying type, not the polymorphic role which they are serving at the moment. * num, Num and all like values return their num representation as a .id. * int, Int and all like values return their int representation as a .id. * Bool, bool and bit all have a bit representation for .id * All other code, objects, references, structures, complex numbers, etc. are compared strictly on the basis of an arbitrary C which Perl will generate to represent their storage, and can be overridden by replacing the default .id method. The other way to think about === would be that it tells you if its LHS *could* be constant-folded onto its RHS (if it were constant for long enough), where =:= tells you if that has already been done. Only ~~ has some sort of "deep" semantics, and I think the documentation warns users s
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
Jedai and I went through some of pugs current implementations. Here's a list of what we expect the operators to return and what they currently do. This does not exactly agree with S03 right now, but is our opinion. Force into a type before comparing values: 42 == 42 - true, same numeric value "42" == 42 - true, same numeric value "42" == "42" - true, same numeric value " 42 " == "42.0" - true, same numeric value " 42 " eq "42.0" - false, different string value 4 eq "4" - true, same string value Well typed value comparison: 42 === 42 - true, the same type "42" === 42 - false, not the same type "42" === "42" - true, the same type " 42 " === "42.0" - false, different value in "natural" type (string values) (1, 2, 3) === (1, 2, 3) - true, same value ([1, 2 ], 3 ) === ([1, 2 ], 3) - true, same value - BROKEN (actually false, since refs are not the same). S03 thinks this is actually OK. [1, 2, 3] === [1, 2, 3] - true, same value, (S03 says that this is actually broken, because references should not be the same (we disagree)) my @foo = (1, 2, 3); my @bar = @foo; @foo === @bar - true, same value. my @foo = ([1, 2], 3); my @bar = @foo; @bar === @foo - true, same value - BROKEN (S03 actually agrees with us here, since the ref is the same in this case) Slot/container equality (this is actually up to debate, but this is what we would expect if it was refaddr($x) == refaddr($y)): [ 1, 2, 3 ] =:= [ 1, 2, 3 ] - false, different containers - BROKEN (actually true) my $foo = [ 1, 2, 3 ]; $foo =:= $foo - true, same container my $foo = [ 1, 2, 3 ]; my $bar := $foo; $bar =:= $foo - true, same container my $foo = [ 1, 2, 3 ]; my $bar = $foo; $bar =:= $foo - true, ref to same container, or false since different container, unsure - currently true my @foo = (1, 2, 3); my @bar = @foo; @foo =:= @bar - false, container should be different - BROKEN (actually true) my @foo = (1, 2, 3); my @bar = @foo; @bar[1] = "moose"; @foo =:= @bar - false, container should be different. This actually works like we expected, appearantly pugs does some sort of COW Under := slot semantics the first test should be false, the second should be true, the third should be true, the fourth should be false, the fifth should be false, and the sixth should be false. -- Yuval Kogman <[EMAIL PROTECTED]> http://nothingmuch.woobling.org 0xEBD27418 pgpNFsdSOd2Lf.pgp Description: PGP signature
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
If we do have deep value equality checks, then "default" == and eq are probably: sub &infix:<==> ( $x, $y ) { +$x === +$y; } sub &infix: ( $x, $y ) { ~$x === ~$y; } So that the compare-as-sometype behavior is retained from perl 5 without introducing new complexity to the objects being compared as strings/numbers. -- Yuval Kogman <[EMAIL PROTECTED]> http://nothingmuch.woobling.org 0xEBD27418 pgpefrROP9pJ6.pgp Description: PGP signature
===, =:=, ~~, eq and == revisited (blame ajs!)
Over at #perl6 we had a short discussion on =:=, ===, and ~~, mostly raised by ajs's discussion on Str items and ===. After a brief discussion we managed to formulate several questions that we feel are slightly to totally unresolved. 1. what is .id on references? Is it related to the memory slot, like refaddr() in Perl 5? 2. is .id *always* a low level type representation of the object's value? It's specced that low level typed items have the same ID when they have the same value. What about complex types? 3. Are these descriptions of the operators correct? ~~ matches the left side to a description on the right side =:= makes sure the objects are actually the same single object (if $x =:= $y and you change $x. then $y. was also changed... is this .id on refs?) Is =:= really eq .id? or more like variable($x).id eq variable($y).id? === makes sure that the values are equivalent ( @foo = ( 1, 2, 3 ); @bar = ( 1, 2, 3); @foo === @bar currently works like that, but @foo = ( [ 1, 2 ], 3 ); @bar = ( [ 1, 2 ], 3 ); @foo === @bar does not (in pugs). This is not useful because we already have this return false with =:=). If they are not correct, why is there an overlap between =:=? Why is it hard to deeply compare values in 2006 without using e.g. Data::Compare? 4. will we have a deep (possibly optimized[1]) equality operator, that *will* return true for @foo = ( [ 1, 2 ], 3 ); @bar = ( [ 1, 2 ], 3 ); op(@foo, @bar)? Is it going to be easy to make the newbies use that when they mean "it's the same", like they currently expect == and eq to work on "simple" values? 5. is there room for a new opperator? =::= makes sure the memory slot is the same (might be different for simple values). refaddr($x) == refaddr($y) in Perl 5 =:= makes sure that .ids are the same, and is useful if the .id method is meaningful for an object. A bit like Test::More::is( $x, $y ) but without the diagnosis in Perl 5, or abusing eq if the object doesn't overload stringification. === makes sure the values are the same even if they are copies/clones/whatever. Data::Compare in Perl 5. A bit like what people overload == for in Perl 5 right now (which confuses "numerical" equality with "true" equality, so we want to phase that out). ~~ makes sure the value on the right side describes the value on the left side. Reminiscient of Test::Deep::cmp_deeply, with all the various matching magic. Thanks, [1] It could, of course, be just =:= && === inside, and it could optimize arrays to check length first, and it could cache checksums and it could do whatever - please don't bring this up as a performance issue, it is one of correctness and ergonomics that must be resolved first. -- Yuval Kogman <[EMAIL PROTECTED]> http://nothingmuch.woobling.org 0xEBD27418 pgpI98L8HHVih.pgp Description: PGP signature