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<expect> 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<Int> or C<Str>. 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<~~>: $_ $x Type of Match Implied Matching Code ====== ===== ===================== ============= ... Array Array arrays are comparable match if $_ »=~=« $x ... Any Any run-time dispatch match 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