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 comparable    match 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<must> not be I<if> 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.<foo> then $y.<foo> 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<int>, C<num> or C<bit>. ===
                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<int> 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
sufficiently of this magical behavior, so they should not be shocked
when C<$huge_tree_1 ~~ $huge_tree_2> takes a long time.

> 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?

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.

> 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

I'd avoid saying "memory", here. Some implementations of Perl 6 might
not know what memory looks like (on a sufficiently abstract VM).

However, otherwise, I think this is what =:= does, except that =:= may
or may not dereference.


In answer to your examples from the other message, I think it's:

        # eq is a bit uglier than I had thought, but not
        # too bad.
        # This is a very C++-like operation where we first
        # establish that the high-level bits are all in line,
        # and then get access to the representation and compare
        # bytes. This assumes:
        # * Str.charset returns a Str::CharSet
        # * Str.encoding returns a Str::Encoding
        # * Str.buf returns the underlying bytes as Buf
        # * a >>===<< b is true in bool context if all a[n]===b[n]
        our Bool multi infix:<eq> ( Str $a, Str $b ) {
                return True unless $a.defined || $b.defined;
                return False unless $a.defined && $b.defined;
                return False unless $a.charset === $b.charset;
                return False unless $a.encoding === $b.encoding;
                my Buf $bufa := $a.buf;
                my Buf $bufb := $b.buf;
                return $bufa >>===<< $bufb;
        }

        our Bool multi infix:<==> ( Int $a, Int $b ) {
                return $a === $b;
        }

        our Bool multi infix:<==> ( Num $a, Num $b) {
                return $a === $b;
        }

        our Bool multi infix:<==> ( Bool $a, Bool $b ) {
                return $a === $b;
        }
        # ... complex, bit, etc.


-- 
Aaron Sherman <[EMAIL PROTECTED]>
Senior Systems Engineer and Toolsmith
"We had some good machines, but they don't work no more." -Shriekback


Reply via email to