On Thu, Jul 13, 2006 at 10:19:24PM -0600, David Green wrote:
: On 7/13/06, Yuval Kogman wrote:
: >So, Larry assisted by Audrey explained the purpose of === vs eqv vs =:=.
: >It makes sense now, but I still feel that as far as ergonomics go 
: >this is not perfect.
: 
: I think I understand it... (my only quibble with the syntax is that 
: === and eqv look like spin-offs of == and eq, but I don't know what 
: to suggest instead (we're running short of combinations of = and : !))

That's partly because they *are* spinoffs, on a metaphorical level.
The === operator is a "mathematically equal", where that implies
equality henceforth and forevermore.  There is also a bit of the
notion that, since a number is a singular thing, you can't treat
any of the bits of a number as mutable.  There's no lvalue substr()
defined on a number, as it were.

The eqv operator, on the other hand, is a "you have to work at figuring
this out by serializing both values conceptually to canonical strings
(think Storable) and see if those are eq.  (Only you don't really go
to all that work, if you can short circuit any of it.)  There is also
the notion (though this breaks down if you look at it too hard) that
a string can be modified in place, so a string value is mutable (at
least from the standpoint of the variable holding it; from the
standpoint of ===, string values are immutable, which is where the
analogy breaks down).

: So there are three basic kinds of comparison: whether the variables 
: are the same (different names, but naming the same thing); whether 
: the values are the same (deep comparison, i.e. recursively all the 
: way down in the case of nested containers); and in-between (shallow 
: comparison, i.e. we compare the top-level values, but we don't work 
: out *their* values too, etc., the way a deep comparison would).  If 
: I've got it right, this is what =:=, eqv, and === give us, 
: respectively.

No, === is also deep.  It's only shallower (or potentially shallower)
in the sense that it treats any mutable object node as a leaf node
rather than changing to "snapshot" semantics like eqv does.

: (When I say "value" I'm thinking of everything that makes up the 
: value, such as type (so the number 3 is different from the string 
: "3"), or details like the encoding for a string, etc.)

Arguably the encoding of a string has nothing to do with its value
most of the time, if the semantics are supposed to be consistent Unicode
semantics at the codepoint or grapheme level.  But yes, by and large
types do have to be included.  Bool::True is a different value from 1,
even though they are often interchangable in many contexts.

: Examples:
: 
:   @x=<foo bar>;
:   @y=<foo bar>;
: 
:   $a=[1, 2, [EMAIL PROTECTED];
:   $b:=$a;
:   $c=[1, 2, [EMAIL PROTECTED];
:   $d=[1, 2, [EMAIL PROTECTED];
: 
: 
:       $a =:= $b;      #true, same variable with two names
:       $a === $b;      #true   _/ $b just another name for $a,
:       $a eqv $b;      #true    \ so comparable at all levels
: 
:       $a =:= $c;      #false, different variables
:       $a === $c;      #true, same elements make up $a and $c
:       $a eqv $c;      #true, same elements therefore same values
: 
:       $a =:= $d;      #false, different variables
:       $a === $d;      #false, [EMAIL PROTECTED] and [EMAIL PROTECTED] are 
different refs
:       $a eqv $d;      #true, values of @x and @y happen to be the same

All correct.

: (Of course, @x eqv @y, @[EMAIL PROTECTED], but not @x=:[EMAIL PROTECTED])
: Note that if $i=:=$j, then $i===$j; and of course if $i===$j, then $i eqv 
: $j.

Those are necessarily true, assuming nobody else is meddling with
our data structures in the middle of our comparison.  If someone is
modifying some mutable component in $i or $j while we're taking a
"snapshot", then we can get into inconsistent states where eqv can
return false despite === being true.

: OK, looking at S03 again, that still isn't correct.  I think my =:= 
: and eqv are all right, but I don't understand exactly what === is 
: supposed to do, or why it's useful.  And how do I do my 
: "shallow-comparison" above?

S03 hasn't been updated to reflect all this yet.  === semantics are
useful for figuring out whether you have a unique key for a hash when
you want to hash on live objects.  eqv is for "dead keys", because
as soon as you've taken a snapshot of your data, you can't modify the
snapshot or dereference any object in your hash key.  eqv semantics
are what Perl 5 hashes use for keys, which is why you can't deref
a hash key directly even if you thought you were putting an object
in as the key.

: (One [1,2] is as good as any other [1,2] -- what's the use of ever 
: having them not compared as the same?  I can see maybe for =:=, since 
: something that doesn't have a name cannot, by definition, have the 
: same name as something else... although even there, it arguably makes 
: sense to consider equivalent anonymous values as "bound" to the same 
: place.  There's only one unique [1,2] in 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

But that's why we have an immutable Seq type (a Tuple type in Haskell
or Python terms, but we avoid the word "tuple" to keep from confusing
database people):

    @a := (1,2);
    @b := (1,2);
    @b[0]++;            # error, attempt to modify (1,2) in platonic heaven

In general we won't have to talk about Seq types much because most
Perl 5 programmers will just use = rather than := and thus end up
copying the sequence values into an array most of the time anyway,
just as it works in Perl 5 already.  Perl 6 just gives you a way to
name the intermediate forms that Perl 5 already deals with internally.

    P5 FAQ: "You can't modify it because it's a list, not an array."
    P6 FAQ: "You can't modify it because it's a Seq, not an Array."

Larry

Reply via email to