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: Another quick one: .as
On Wed, 2006-07-12 at 17:52 -0700, Larry Wall wrote: > On Wed, Jul 12, 2006 at 12:51:57PM -0400, Aaron Sherman wrote: > : I would assume that all classes automatically define: > : > : multi submethod *infix: ($self: $?CLASS) { $self } > > Hmm, "as" is really only intended for explicit type mutation (which > can work either by role mixin or by new object construction). It's > not intended to give Perl a different "view" of an unmutated object. Thanks. I think I got compile-time polymorphism confused with run-time mutation. These are moose of vastly different colors. -- 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 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
S29 demerge and API document plan
Audrey has asked me to split S29 AKA Perl6/Spec/Functions.pod up due to its rapidly expanding size. The strategy that she suggested is basically what I'm leaning toward, but I wanted to get feedback (esp. from Larry and other Synopsians). I want to be clear, I'm not asking for help coming up with a way to do this, just trying to see if I'm going to completely hose The Plan(tm). Something like this could easily be a week-long thread, and I don't want to go there unless I really have to. "S29: Functions" will be an overview, and will contain a sectional format as it does now, broken up by high-level modules. This isn't in question, since three of us who have worked on it have found this to be the best way to approach it, and it's not the best use of my time to go re-writing the whole structure, anyway. Each section will lead with a blurb about the module and a reference to its API document. For the most part, these sections will be populated with functions, but method variants where there is a functional equivalent will only get a passing mention and no signature. Method-only entries will not be mentioned in this document, and instead will be moved out to the API document specific to the module/class in question. Modules which are very self-contained (e.g. Math::Trig) will JUST get a blurb, suggesting that the reader peruse the appropriate API document. Modules which have relatively generic OS or other non-core language features may be abbreviated, and some functions may get little or no mention. These details will be moved out to the API document for the module in question. Constants will be entirely in the API document, but will probably get a short note in S29. A "Compatibility" section will be added which will break all of the Perl 5 functions from perlfunc down into several categories: * As-is - the old usage is essentially unchanged (e.g. sprintf) * Altered - The new usage is functionally different, but similar (or a subset, e.g. eval) * Name only - The new usage has almost nothing to do with the old (e.g. each) * Compatibility - The old name is supported, but deprecated (e.g. chr) * Unsupported - The old name is gone (e.g. waitpid) If a function is not exported by default, it will also be noted in this section. In this way, even though S29 may not contain every function available to Perl 6 programmers as a builtin, it will at least give Perl 5 programmers a sense of what happened to what they knew. The API documents should probably be the more authoritative reference for implementing P6 core libraries. -- Aaron Sherman <[EMAIL PROTECTED]> http://www.ajs.com/~ajs/ Mushroom Photography: http://mush.ajs.com/news/
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
Run time dispatch on ~~
I'm told that I did a terrible job of making my point in the === thread, and nothingmuch asked me on IRC to re-state my concerns. I'll do so briefly, and then give examples. Please do have a look at the examples, just in case I'm not clear. Overview: ~~ is great. It matches on all kinds of useful right-hand-sides like regexes, strings, methods, your neighbor's kids, you-name-it. The only problem that I have is ~~ matching against an unknown type (Any~~Any). In this case, the programmer cannot know what it is that they're getting themselves into, and for the life of me, I can't see why Perl would do anything other than an only slightly smart comparison there, since that's obviously what the programmer had in mind. However, S03 specs that ~~ will do a run-time dispatch based on the type of that value at the time. Matching Arrays (@~~@) is just a hyperoperated case of the same problem, except for the case where the array on the right-hand-side can be typed at compile-time or is a list that can be coerced painlessly into such a typed array. Then there's no dispatch at run-time. Solution: Ok, so first let me re-propose my solution: Any~~Any and @~~@ are compile-time dispatched to =~= and >>=~=<< respectively (no, I'm not married to the name, and perhaps eqv is better for this, I don't know), which has some smarts about comparing values in meaningful ways, and which programmers know to override if they really need special matching semantics, but basically is just a very slightly smarter ===. Regexes are compared, not executed. Code is compared, not executed. Examples: Now, let's look at some of the good that ~~ does for us: $a ~~ "Some string" # sameness $a ~~ 5 # sameness $a ~~ ->{...} # test $a ~~ /.../ # regex matching That's great, and we don't want to mess with any of it. But, then we have: $a ~~ $b# uh... something We can't even say what it does, much less why it's useful. It does "match" whatever that is. Sure, it's great for implementing your own ~~, but that's about it. The even worse: @a ~~ @b# uh... lots of something looks like array comparison to the casually misinformed user, but is actually a run-time, hyperized vector dispatch... Now, I do think people will want to: @a ~~ ( /^\d+$/, /^\w+$/, /^\s+$/ ) but we can coerce that into a typed array at compile time, so there's no problem. Going with my suggestion would mean that ~~ is still very powerful, just not opaque. You would have to ask for it to activate a particular superpower by giving it a right-hand-side that has a type, or expect a fairly mundane comparison to be performed. The _security_ implications will likely get sorted out, but I still forsee some major end-user bogglage when $a~~$b is true, even though they have no relationship to each other that was obvious to the programmer who wrote the statement. Keep in mind that if you have an Any and you want to match against it smartly, you can always request your poison: $a ~~ ($b as Regex) -- 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!) -- 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
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: Run time dispatch on ~~
On Thu, Jul 13, 2006 at 15:44:33 -0400, Aaron Sherman wrote: > Now, let's look at some of the good that ~~ does for us: > > $a ~~ "Some string" # sameness > $a ~~ 5 # sameness > $a ~~ ->{...} # test > $a ~~ /.../ # regex matching > > That's great, and we don't want to mess with any of it. > > But, then we have: > > $a ~~ $b# uh... something One compelling reason to have them behave exactly the same is to allow refactoring. If i'm using the same pattern on several inputs i'd like to maybe delegate this to a helper sub that will actually run the ~~ for me, in some way, and i'd like 100% compatibility. 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 -- Yuval Kogman <[EMAIL PROTECTED]> http://nothingmuch.woobling.org 0xEBD27418 pgp8KEQiTHBTj.pgp Description: PGP signature
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 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!) -- 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 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
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
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
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
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