Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

===, =:=, ~~, eq and == revisited (blame ajs!)

11 views
Skip to first unread message

Yuval Kogman

unread,
Jul 12, 2006, 12:25:08 PM7/12/06
to perl6-l...@perl.org
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.<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 =:=).

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 <nothi...@woobling.org>
http://nothingmuch.woobling.org 0xEBD27418

Yuval Kogman

unread,
Jul 12, 2006, 12:36:49 PM7/12/06
to perl6-l...@perl.org
If we do have deep value equality checks, then "default" == and eq
are probably:

sub &infix:<==> ( $x, $y ) {
+$x === +$y;
}

sub &infix:<eq> ( $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

unread,
Jul 12, 2006, 1:00:29 PM7/12/06
to perl6-l...@perl.org
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.

Aaron Sherman

unread,
Jul 12, 2006, 4:16:13 PM7/12/06
to Yuval Kogman, perl6-l...@perl.org
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 <a...@ajs.com>
Senior Systems Engineer and Toolsmith
"We had some good machines, but they don't work no more." -Shriekback


Jonathan Scott Duff

unread,
Jul 12, 2006, 4:32:29 PM7/12/06
to Aaron Sherman, Yuval Kogman, perl6-l...@perl.org
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 comparable match 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
du...@pobox.com

Aaron Sherman

unread,
Jul 12, 2006, 5:58:03 PM7/12/06
to du...@pobox.com, Yuval Kogman, perl6-l...@perl.org
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?

Yuval Kogman

unread,
Jul 12, 2006, 6:44:22 PM7/12/06
to Aaron Sherman, perl6-l...@perl.org
On Wed, Jul 12, 2006 at 16:16:13 -0400, Aaron Sherman wrote:

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

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<must> not be I<if> 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

unread,
Jul 12, 2006, 6:45:50 PM7/12/06
to Aaron Sherman, du...@pobox.com, perl6-l...@perl.org
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

unread,
Jul 12, 2006, 6:50:14 PM7/12/06
to Aaron Sherman, perl6-l...@perl.org
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"

Aaron Sherman

unread,
Jul 12, 2006, 10:06:36 PM7/12/06
to Aaron Sherman, du...@pobox.com, perl6-l...@perl.org
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<Any ~~ Any> 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 ~~?

Darren Duncan

unread,
Jul 13, 2006, 3:55:30 AM7/13/06
to perl6-l...@perl.org
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 ===.
<snip>

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 appropriate and that something else should be
used instead, something that isn't invoked when working with hash
keys.

I may have forgotten to raise something else, but there's that for now.

-- Darren Duncan

Yuval Kogman

unread,
Jul 13, 2006, 10:36:20 AM7/13/06
to Darren Duncan, perl6-l...@perl.org
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

unread,
Jul 13, 2006, 2:32:08 PM7/13/06
to perl6-l...@perl.org
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

Larry Wall

unread,
Jul 13, 2006, 3:50:19 PM7/13/06
to perl6-l...@perl.org
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

Larry Wall

unread,
Jul 13, 2006, 3:59:19 PM7/13/06
to perl6-l...@perl.org
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<leg> and the
polymorphic semantics should probably be C<cmp>.

Larry

Darren Duncan

unread,
Jul 14, 2006, 12:14:34 AM7/14/06
to perl6-l...@perl.org
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

David Green

unread,
Jul 14, 2006, 12:19:24 AM7/14/06
to perl6-l...@perl.org
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=<foo bar>;
@y=<foo bar>;

$a=[1, 2, \@x];
$b:=$a;
$c=[1, 2, \@x];
$d=[1, 2, \@y];


$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, \@x and \@y are different refs
$a eqv $d; #true, values of @x and @y happen to be the same


(Of course, @x eqv @y, @x===@y, but not @x=:=@y.)
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

Jonathan Lang

unread,
Jul 14, 2006, 12:55:15 AM7/14/06
to perl6language,
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

Yuval Kogman

unread,
Jul 14, 2006, 1:17:39 AM7/14/06
to perl6-l...@perl.org
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

unread,
Jul 14, 2006, 1:16:54 AM7/14/06
to Jonathan Lang, perl6language,
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:<eq> ( Any $x, Any $y ) {
~$x === ~$y
}


Jonathan Lang

unread,
Jul 14, 2006, 1:36:41 AM7/14/06
to Jonathan Lang, perl6language,
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:<eq> ( 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

Darren Duncan

unread,
Jul 14, 2006, 1:56:59 AM7/14/06
to perl6-l...@perl.org
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

Darren Duncan

unread,
Jul 14, 2006, 2:52:14 AM7/14/06
to perl6-l...@perl.org
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

Smylers

unread,
Jul 14, 2006, 6:42:24 AM7/14/06
to perl6-l...@perl.org
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

Yuval Kogman

unread,
Jul 14, 2006, 8:56:32 AM7/14/06
to Smylers, perl6-l...@perl.org
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.

Smylers

unread,
Jul 14, 2006, 9:26:29 AM7/14/06
to perl6-l...@perl.org
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

Mark A. Biggar

unread,
Jul 14, 2006, 10:55:15 AM7/14/06
to Darren Duncan, perl6-l...@perl.org
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 '>'.

--
ma...@biggar.org
mark.a...@comcast.net

Dave Whipp

unread,
Jul 14, 2006, 12:22:10 PM7/14/06
to perl6-l...@perl.org
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.

Dr.Ruud

unread,
Jul 14, 2006, 12:55:17 PM7/14/06
to perl6-l...@perl.org
"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."


Darren Duncan

unread,
Jul 14, 2006, 3:46:10 PM7/14/06
to perl6-l...@perl.org
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

Jonathan Lang

unread,
Jul 14, 2006, 3:48:58 PM7/14/06
to perl6language,
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: "+@a == +@b".

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

Larry Wall

unread,
Jul 14, 2006, 3:55:35 PM7/14/06
to perl6-l...@perl.org
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

Darren Duncan

unread,
Jul 14, 2006, 3:55:16 PM7/14/06
to perl6-l...@perl.org
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

Darren Duncan

unread,
Jul 14, 2006, 4:18:06 PM7/14/06
to perl6-l...@perl.org
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

Yuval Kogman

unread,
Jul 14, 2006, 5:26:08 PM7/14/06
to Dave Whipp, perl6-l...@perl.org
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
!=

Dr.Ruud

unread,
Jul 14, 2006, 5:33:25 PM7/14/06
to perl6-l...@perl.org
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

--

Charles Bailey

unread,
Jul 14, 2006, 5:49:51 PM7/14/06
to David Green, perl6-l...@perl.org
On 7/14/06, David Green <david...@telus.net> 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

Larry Wall

unread,
Jul 14, 2006, 6:04:40 PM7/14/06
to perl6-l...@perl.org
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, \@x];
: $b:=$a;
: $c=[1, 2, \@x];
: $d=[1, 2, \@y];
:
:
: $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, \@x and \@y are different refs
: $a eqv $d; #true, values of @x and @y happen to be the same

All correct.

: (Of course, @x eqv @y, @x===@y, but not @x=:=@y.)


: 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

Smylers

unread,
Aug 13, 2006, 3:47:43 AM8/13/06
to perl6-l...@perl.org

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

David Green

unread,
Aug 13, 2006, 12:46:13 PM8/13/06
to perl6-l...@perl.org
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 people,
and not a single object trying to scam the company.)


For reference, I'm including my trivial but technically correct
examples from a previous message. (Of course, I'm ignoring funky
details like what would happen if your variables are changing while
you're trying to compare them, etc.)

>Examples:
>
> @x=<foo bar>;
> @y=<foo bar>;
>
> $a=[1, 2, \@x];
> $b:=$a;
> $c=[1, 2, \@x];
> $d=[1, 2, \@y];
>
>
> $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, \@x and \@y are different refs
> $a eqv $d; #true, values of @x and @y happen to be the same


-David

David Green

unread,
Aug 13, 2006, 3:51:44 PM8/13/06
to perl6-l...@perl.org
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]]?

$a=\@a should be different from (!===) $b=\@b 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 $b=\@b and I do $b[0]++? It
might look superficially as though I were changing $b, but $b still
is \@b -- @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

Smylers

unread,
Aug 14, 2006, 1:41:20 PM8/14/06
to perl6-l...@perl.org
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 = \@orig;

and:

my $new = [@orig];

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

Smylers

unread,
Aug 14, 2006, 1:55:24 PM8/14/06
to perl6-l...@perl.org
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

Dr.Ruud

unread,
Aug 15, 2006, 12:08:04 PM8/15/06
to perl6-l...@perl.org
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/

David Green

unread,
Aug 15, 2006, 4:32:29 PM8/15/06
to perl6-l...@perl.org
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

David Green

unread,
Aug 15, 2006, 4:51:20 PM8/15/06
to perl6-l...@perl.org
On 8/14/06, Smylers wrote:
>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.

But is Perl 5 the best place to start? It's something many of us are
used to, but that doesn't mean it's the best solution conceptually,
even if it was the most reasonable way to implement it in P5.

The reason I think it's an implementation wart is that an array --
thought of as a single, self-contained lump -- is different from a
reference or pointer to some other variable. Old versions of Perl
always eagerly exploded arrays, so there was no way to refer to an
array as a whole; put two arrays together and P5 (or P4, etc.) thinks
it's just one big array or list.
Then when references were introduced, "array-refs" provided a way to
encapsulate arrays so we could work with them as single lumps. It's
not the most elegant solution, but being able to nest data structures
at all was a tremendous benefit, and it was backwards-compatible.

P6 doesn't have to be that backwards-compatible -- it already isn't.
P6 more naturally treats arrays as lumps; this may or may not be
*implemented* using references as in P5, but it doesn't have to -- or
at least, it doesn't have to *look* as though that's how it's doing
it. Conceptually, an array consisting only of constant literals,
like (1,2,3), isn't referring to anything, so it doesn't need to
behave that way.

>The difference between:
> my $new = \@orig;
>and:
> my $new = [@orig];
>
>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.

I agree that \@orig should be distinct from [@orig] -- in the former
case, we're deliberately taking a reference to the @orig variable.
What I don't like is that [@orig] is distinct from [@orig] -- sure,
I'm doing something similar to Array->new(1,2) followed by another
Array->new(1,2), but I still want them to be the same, just as I want
Str->new("foo") to be the same as Str->new("foo"). They're just
constants, they should compare equally regardless of how I created
them. (And arrays should work a lot like strings, because at some
conceptual level, a string is an array [of characters].)

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

Except [1,2] can look like (1,2) in P6 because it automatically
refs/derefs stuff so that things Just Work. That's good, because you
shouldn't have to be referencing arrays yourself (hence my point
above about an array conceptually being a single lump). But if we're
going to hide the [implementational] distinction in some places, we
should hide it everywhere.

Actually, my point isn't even about arrays per se; that's just the
implementation/practical side of it. You can refer to a scalar
constant too:
perl -e 'print \1, \1'
SCALAR(0x8104980)SCALAR(0x810806c)

They're different because the *references* are different, but I don't
care about that. A reference to a constant value is kind of
pointless, because the value isn't going to change. References to
*variables* are useful, because you never know what value that
variable might have, and refs give you a pointer to the current value
of the variable at any time.

The fact that it's even possible to take a reference to a literal is
kind of funny, really; but since in P5 you had to be explicit about
(de)referencing, it didn't hurt, and you could maybe even find some
cute ways to take advantage of it (such as an easy way to get unique
IDs out of the str/numification of a ref?). P6 just lets you gloss
over certain ref/deref distinctions that in a perfect world wouldn't
have existed in the first place.

Leibniz's "identity of indiscernibles" is a perfectly practical
principle to pursue in programming. Now \@orig may be discernible
from [@orig] or [1, @orig] from [1, @other], but \1 is completely the
same as \1 in all ways -- all ways except for being able to get a
representation of its memory location. And that's not anything about
"1", that's a bit of metadata about the reference itself -- something
that definitely is based on the implementation.

(I can imagine some other implementation where in a ridiculous
attempt to optimise for minimal memory footprint, everything with a
value of 1 points to the same address. When I say "$a=1; $a++", $a
first points to 0x1234567, and when I increment it, I don't change
the bits in that location, instead $a changes to point to address
0x3456789, where my unique 2 value is stored. Then the only way to
differentiate \1 from \1 is to generate some arbitrary unique ID.
Which would be silly.)

Anyway, I hope I'm making sense about why \1 !=== \1, etc. seems a
bit unnatural to me.


-David

Darren Duncan

unread,
Aug 15, 2006, 9:38:54 PM8/15/06
to perl6-l...@perl.org
It seems to me that there is some confusion being given in this
thread and the most recent parts of its predecessor (which can lead
to FUD in the wrong hands), so I'll briefly try to clear it up, as I
would like to think I understand the issues.

At 2:51 PM -0600 8/15/06, David Green wrote:
>On 8/14/06, Smylers wrote:
>>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.

There are no implementation details leaking out, but rather we are
just dealing with the declared interface behaviour of different types
and operators.

>I agree that \@orig should be distinct from [@orig] -- in the former
>case, we're deliberately taking a reference to the @orig variable.
>What I don't like is that [@orig] is distinct from [@orig] -- sure,
>I'm doing something similar to Array->new(1,2) followed by another
>Array->new(1,2), but I still want them to be the same, just as I
>want Str->new("foo") to be the same as Str->new("foo"). They're
>just constants, they should compare equally regardless of how I
>created them. (And arrays should work a lot like strings, because
>at some conceptual level, a string is an array [of characters].)

You are right, but we have both Seq and Array types, so depending
which one you use, you want either the === or eqv operators to do
what you want. There is no reason that === should say 2 Array are
equal; we have eqv for that, or use 2 Seq instead of 2 Array if you
want === to return true on the same values.

So, (1,2) always === and eqv (1,2), but [1,2] only eqv [1,2] and
[1,2] generally !=== [1,2].

First of all, in Perl 6, there are no separate "arrays" and "array
refs"; we simply have the 'Array' type, which is treated as a lump on
its own.

More generally, there are no "reference" types in Perl 6. We do have
a concept of multiple symbols being aliases for the same container,
and they only come to be that way if they are explicitly aliased,
such as with "$a := $b"; only in those cases, the operator =:=, which
sees if 2 symbols represent the same container, would return true.
If you create 2 values separately and don't explicitly alias them
like that, =:= will return false, even if the 2 containers have

appearances of the same value.

Both the === and eqv operators test the actual values of 2
containers, but that their semantics differ in regards to mutable
containers. Given an immutable container/type, such as a number or
Str or Seq, both will always return true if the values are the same.
With a mutable container, such as an Array, only eqv will return true
if the value is the same, and === will return false for 2 containers
having the same value.

The difference between === and eqv is that, if you have 2 symbols, $a
and $b, and $a === $b returns true, then that result is guaranteed to
be eternal if you don't assign to either symbol afterwards. For a
mutable type like an Array, === returns false on 2 containers because
it can't guarantee that someone else holding another symbol for
either container won't change its content, and so $a or $b could
change after we made the === test, without us causing that to happen,
and so for mutable types, === only returns true for 2 aliases,
because that is the most it can guarantee that they will be the same.
By contrast, eqv does not make the eternal guarantee, and works only
on snapshots, so eqv can safely deep-compare mutable types like
Arrays, since even if one of them changes afterwards, it doesn't
matter, since eqv only guaranteed them equal for that point in time
when it executed.

It is important for some applications to distinguish whether the
result of an equivalence test will be valid eternally or not, and
hence we have multiple analagous types and multiple equality tests,
where pairwise they distinguish eternally vs snapshot. We can say
exactly what we mean, and it is unambiguous, which is a GOOD thing.

-- Darren Duncan

Markus Laire

unread,
Aug 16, 2006, 4:42:56 AM8/16/06
to Darren Duncan, perl6-l...@perl.org
On 8/16/06, Darren Duncan <dar...@darrenduncan.net> wrote:
> Both the === and eqv operators test the actual values of 2
> containers, but that their semantics differ in regards to mutable
> containers. Given an immutable container/type, such as a number or
> Str or Seq, both will always return true if the values are the same.
> With a mutable container, such as an Array, only eqv will return true
> if the value is the same, and === will return false for 2 containers
> having the same value.
>
> The difference between === and eqv is that, if you have 2 symbols, $a
> and $b, and $a === $b returns true, then that result is guaranteed to
> be eternal if you don't assign to either symbol afterwards. For a
> mutable type like an Array, === returns false on 2 containers because
> it can't guarantee that someone else holding another symbol for
> either container won't change its content, and so $a or $b could
> change after we made the === test, without us causing that to happen,
> and so for mutable types, === only returns true for 2 aliases,
> because that is the most it can guarantee that they will be the same.
> By contrast, eqv does not make the eternal guarantee, and works only
> on snapshots, so eqv can safely deep-compare mutable types like
> Arrays, since even if one of them changes afterwards, it doesn't
> matter, since eqv only guaranteed them equal for that point in time
> when it executed.

So do you mean that this code
$a = "One";
$b = "One";
$aa := $a;
say "Same before" if $a === $b;
$aa = "Two";
say "Same after" if $a === $b;
would print
Same before
Same after
because here I have "2 symbols, $a and $b, and $a === $b returns true"
and I don't assign to either symbol afterwards - and you seem to be
saying that only with mutable types like Array can you change the
contents via another symbol ($aa here).

But according to S03 this would only print "Same before", because the
assigment to $aa would change $a
<quote>
A new form of assignment is present in Perl 6, called binding, used in
place of typeglob assignment. It is performed with the := operator.
Instead of replacing the value in a container like normal assignment,
it replaces the container itself. For instance:

my $x = 'Just Another';
my $y := $x;
$y = 'Perl Hacker';

After this, both $x and $y contain the string "Perl Hacker", since
they are really just two different names for the same variable.
</quote>

--
Markus Laire

Darren Duncan

unread,
Aug 16, 2006, 6:08:55 AM8/16/06
to perl6-l...@perl.org
At 11:42 AM +0300 8/16/06, Markus Laire wrote:
>On 8/16/06, Darren Duncan <dar...@darrenduncan.net> wrote:
>>The difference between === and eqv is that, if you have 2 symbols, $a
>>and $b, and $a === $b returns true, then that result is guaranteed to
>>be eternal if you don't assign to either symbol afterwards.
>
>So do you mean that this code
> $a = "One";
> $b = "One";
> $aa := $a;
> say "Same before" if $a === $b;
> $aa = "Two";
> say "Same after" if $a === $b;
>would print
> Same before
> Same after
>because here I have "2 symbols, $a and $b, and $a === $b returns true"
>and I don't assign to either symbol afterwards - and you seem to be
>saying that only with mutable types like Array can you change the
>contents via another symbol ($aa here).

Thanks for catching that typo.

What you are saying with your above example is correct, and I knew
about that before, but it slipped my mind when I wrote my explanation
before.

I'll try saying what I meant differently here:

The difference between === and eqv is that, if you have 2 symbols, $a
and $b, and $a === $b returns true, then that result is guaranteed to

be eternal if you don't assign to either symbol [or other symbols
aliased to either] afterwards.

The idea is that, the degree to which === examines 2 variables to
consider them equal or not is only so far as they are immutable. So
if you say "$foo = $bar", and then "$baz === $foo" returns true, then
a subsequent assignment to or type-allowed mutation of $bar won't
invalidate that $baz === $foo, but an assignment to $foo would.

-- Darren Duncan

Dr.Ruud

unread,
Aug 16, 2006, 6:17:10 AM8/16/06
to perl6-l...@perl.org
"Markus Laire" schreef:

> my $x = 'Just Another';
> my $y := $x;
> $y = 'Perl Hacker';
>
> After this, both $x and $y contain the string "Perl Hacker", since
> they are really just two different names for the same variable.
> </quote>

So "$x === Sy" stil holds.

Markus Laire

unread,
Aug 16, 2006, 8:51:42 AM8/16/06
to Dr.Ruud, perl6-l...@perl.org
On 8/16/06, Dr.Ruud <rvtol...@isolution.nl> wrote:
> "Markus Laire" schreef:
>
> > my $x = 'Just Another';
> > my $y := $x;
> > $y = 'Perl Hacker';
> >
> > After this, both $x and $y contain the string "Perl Hacker", since
> > they are really just two different names for the same variable.
> > </quote>
>
> So "$x === Sy" stil holds.

Exactly, and because of that $a === $b does NOT hold in my example.
($a would be "Two", $b would be "One")

--
Markus Laire

Charles Bailey

unread,
Aug 16, 2006, 9:21:56 AM8/16/06
to Darren Duncan, perl6-l...@perl.org
On 8/16/06, Darren Duncan <dar...@darrenduncan.net> wrote:
> At 11:42 AM +0300 8/16/06, Markus Laire wrote:
> >On 8/16/06, Darren Duncan <dar...@darrenduncan.net> wrote:
> >>The difference between === and eqv is that, if you have 2 symbols, $a
> >>and $b, and $a === $b returns true, then that result is guaranteed to
> >>be eternal if you don't assign to either symbol afterwards.
> >
> >So do you mean that this code
> > $a = "One";
> > $b = "One";
> > $aa := $a;
> > say "Same before" if $a === $b;
> > $aa = "Two";
> > say "Same after" if $a === $b;
> >would print
> > Same before
> > Same after
> >because here I have "2 symbols, $a and $b, and $a === $b returns true"
> >and I don't assign to either symbol afterwards - and you seem to be
> >saying that only with mutable types like Array can you change the
> >contents via another symbol ($aa here).
>
> Thanks for catching that typo.
>
> What you are saying with your above example is correct, and I knew
> about that before, but it slipped my mind when I wrote my explanation
> before.
>
> I'll try saying what I meant differently here:
>
> The difference between === and eqv is that, if you have 2 symbols, $a
> and $b, and $a === $b returns true, then that result is guaranteed to
> be eternal if you don't assign to either symbol [or other symbols
> aliased to either] afterwards.

This is where the "eternal" part starts to confuse me (not picking on
your wording, but on the semantics). For example, suppose I say

<0> $a = "One";
<1> $b = "One";
<2> $aa := $a;
<3> say "Immutidentical" if $a === $b;

As I understand it, I'll see "Immutidentical".

If I insert the C<$aa = "Two"> before line 3, then I won't see "Immutidentical".

What happens if I insert the C<$aa = "Two"> before line 255? In other
words, can I rely on P6 to know at line 3 that there's an alias out
there by which C<$a> _might_ change without assignment later (i.e. the
guarantee that "$a and $b will remain the same unless you assign to
one" might be violated)?

What happens if the C<$aa = "Two"> is in an eval-equivalent, so the
compiler can't see it before runtime? Does the fact that the alias
exists violate the guarantee of immutability, or does the guarantee
just mean that at the instant the test is executed, both the contents
and container are the same? (If the latter, I'm not sure in what
practical situations I'd use it.)

If I've -- once again -- totally missed the boat, please be patient.

Markus Laire

unread,
Aug 16, 2006, 9:56:56 AM8/16/06
to Darren Duncan, perl6-l...@perl.org
On 8/16/06, Darren Duncan <dar...@darrenduncan.net> wrote:
> I'll try saying what I meant differently here:
>
> The difference between === and eqv is that, if you have 2 symbols, $a
> and $b, and $a === $b returns true, then that result is guaranteed to
> be eternal if you don't assign to either symbol [or other symbols
> aliased to either] afterwards.
>
> The idea is that, the degree to which === examines 2 variables to
> consider them equal or not is only so far as they are immutable. So
> if you say "$foo = $bar", and then "$baz === $foo" returns true, then
> a subsequent assignment to or type-allowed mutation of $bar won't
> invalidate that $baz === $foo, but an assignment to $foo would.

IMHO the text "a subsequent assignment to or" is useless here because
I don't think any subsequent assignment to $bar could ever affect
$foo, even if they were mutable types:
$bar = [1,2];
$foo = $bar;
...
$bar = 123; # This doesn't affect $foo

Of course, type-allowed mutation of $bar will affect $foo if $bar is
mutable type.

Still, thanks for clarification - I misunderstood what you meant with
"someone else holding another symbol".

--
Markus Laire

Dr.Ruud

unread,
Aug 16, 2006, 10:25:13 AM8/16/06
to perl6-l...@perl.org
"Markus Laire" schreef:
> Dr.Ruud:
>> Markus Laire:

>>> my $x = 'Just Another';
>>> my $y := $x;
>>> $y = 'Perl Hacker';
>>>
>>> After this, both $x and $y contain the string "Perl Hacker", since
>>> they are really just two different names for the same variable.
>>> </quote>
>>

>> So "$x === Sy" stil[l] holds.


>
> Exactly, and because of that $a === $b does NOT hold in my example.
> ($a would be "Two", $b would be "One")

Yes, sorry for my over-compact reply. Where Darren wrote:

The difference between === and eqv is that, if you have 2 symbols, $a
and $b, and $a === $b returns true, then that result is guaranteed to
be eternal if you don't assign to either symbol afterwards.

I think he meant something like "to either symbol (or alias)".
But read S03 for an exacter description.


I also wondered why a "simple" array (for example containing only value
type objects) whould not C<===> its copy.
But with .SKID that must be easy to handle.


Comparing strings in Perl5, using NFKD:

perl5 -MUnicode::Normalize -we '
($\, $,) = ("\n", "\t") ;
$x = qq{Henry IV} ;
$y = qq{Henry \x{2163}} ;
print qq{<$x>}, qq{<$y>}, length $x, length $y, $x eq $y ? 1 : 0 ;
# $x = NFKD $x ;
$y = NFKD $y ;
print qq{<$x>}, qq{<$y>}, length $x, length $y, $x eq $y ? 1 : 0 ;
'
Wide character in print at -e line 5.
<Henry IV> <Henry â.£> 8 7 0
<Henry IV> <Henry IV> 8 8 1


How will the Str type do this?

Larry Wall

unread,
Aug 16, 2006, 6:11:59 PM8/16/06
to perl6-l...@perl.org
On Wed, Aug 16, 2006 at 04:25:13PM +0200, Dr.Ruud wrote:
: Comparing strings in Perl5, using NFKD:

:
: perl5 -MUnicode::Normalize -we '
: ($\, $,) = ("\n", "\t") ;
: $x = qq{Henry IV} ;
: $y = qq{Henry \x{2163}} ;
: print qq{<$x>}, qq{<$y>}, length $x, length $y, $x eq $y ? 1 : 0 ;
: # $x = NFKD $x ;
: $y = NFKD $y ;
: print qq{<$x>}, qq{<$y>}, length $x, length $y, $x eq $y ? 1 : 0 ;
: '
: Wide character in print at -e line 5.
: <Henry IV> <Henry �.�> 8 7 0

: <Henry IV> <Henry IV> 8 8 1
:
:
: How will the Str type do this?

That'd just be:

eqv($x, $y, :(NFKD $^s))

or some such, give or take a little notation in the signature to force MMD
to match a Str and coerce to NFKD. This is mentioned in S03 as a subproblem
of the general canonicalization/collation problem. It should be using the
same underlying semantics as

cmp($x, $y, :(NFKD $_))

or
sort :(NFKD $_), @strings;

Larry

David Green

unread,
Aug 16, 2006, 6:52:08 PM8/16/06
to perl6-l...@perl.org
On 8/16/06, Dr.Ruud wrote:
>I also wondered why a "simple" array (for example containing only value
>type objects) whould not C<===> its copy.
>But with .SKID that must be easy to handle.

That's what I was wondering that started off this thread. I
understand (more or less, I think), why it *does* work that way; I'm
just not sure why we'd *want* it to work that way.

And maybe the answer is that in an ideal world, we wouldn't want it
-- but in practice, that simply isn't feasible, so instead we get
mutables and immutables and most of the time I'll just use "eqv" and
everything will DWIM and it doesn't matter, and on the rare occasions
when I really need to do === stuff, I'll just have to cope with it.
(Or maybe subclass stuff with my own SKIDs to make it work the way I
want, whatever.)

That's fine, trade-offs are a fact of life. But nobody's actually
said that, so I don't know whether I'm misunderstanding something
still, whether I just haven't clearly explained what the heck I mean
(or both, always a distinct possibility!).


-David

David Green

unread,
Aug 16, 2006, 6:55:27 PM8/16/06
to perl6-l...@perl.org
On 8/16/06, Charles Bailey wrote:
>This is where the "eternal" part starts to confuse me (not picking on
>your wording, but on the semantics).

I'll pick on the wording (wording should always be picked on -- not
to be pedantic (OK, I like to be pedantic, but that's not the *only*
reason!), but because it really is an advantage to develop
terminology that's as precise and pretty as possible).

Maybe values can be considered "eternal", in some philosophical
platonic sense, but variables certainly aren't (eventually your
program will reach the end or the sun will explode or something).
"Permanent", maybe...

>What happens if I insert the C<$aa = "Two"> before line 255? In other
>words, can I rely on P6 to know at line 3 that there's an alias out
>there by which C<$a> _might_ change without assignment later (i.e. the
>guarantee that "$a and $b will remain the same unless you assign to
>one" might be violated)?

...but there's nothing permanent either really, because you can
always change any variable you like, later on at line 255. (Unless
the variable is a constant, which is not the same thing as being
immutable even though those words are fairly synonymous, i.e. yet
more confusing terminology.)

What we're really talking about is action-at-a-distance: one variable
changing its value because *something else* changed -- some other
variable that was somehow "contained inside" the first one.

Not to be confused with changing some other variable that is really
the same variable because they were bound together: $a:=$b. Should I
call that two variables (somehow "linked" or bound together)? Or
would it be better (easier, less confusing) to call it *one* variable
that has two names? (Still nothing to be described as "permanent"
here, because I can always unbind them later on, and have $a and $b
being two completely separate variables, right?)

I find myself tempted to talk in temporal terms to explain the issue,
and that's a natural way to frame examples, but the language of
examples doesn't seem to be that good for explaining the concepts.
Whether stuff may or may not change isn't the point; what it comes
down to is referring to a variable itself vs. evaluating it.


-David

Dr.Ruud

unread,
Aug 16, 2006, 7:39:51 PM8/16/06
to perl6-l...@perl.org
Larry Wall schreef:
> Dr.Ruud:

>> Comparing strings in Perl5, using NFKD:
>>
>> perl5 -MUnicode::Normalize -we '
>> ($\, $,) = ("\n", "\t") ;
>> $x = qq{Henry IV} ;
>> $y = qq{Henry \x{2163}} ;
>> print qq{<$x>}, qq{<$y>}, length $x, length $y, $x eq $y ? 1 : 0 ;
>> # $x = NFKD $x ;
>> $y = NFKD $y ;
>> print qq{<$x>}, qq{<$y>}, length $x, length $y, $x eq $y ? 1 : 0 ;
>> '
>> Wide character in print at -e line 5.

>> <Henry IV> <Henry ?.?> 8 7 0


>> <Henry IV> <Henry IV> 8 8 1
>>
>>
>> How will the Str type do this?
>
> That'd just be:
>
> eqv($x, $y, :(NFKD $^s))
>

> [...]

Thanks. Is it also possible to define an NKFD_Str type so that you can
code C<$x === $y>, and the NKFD-stuff is done because of the type's
.SKID? (Can a "type" have a (type-wide) .SKID?)

David Green

unread,
Aug 17, 2006, 1:16:36 AM8/17/06
to perl6-l...@perl.org
On 8/15/06, Darren Duncan wrote:
>At 2:51 PM -0600 8/15/06, David Green wrote:
[...]

>You are right, but we have both Seq and Array types, so depending
>which one you use, you want either the === or eqv operators to do
>what you want. There is no reason that === should say 2 Array are
>equal; we have eqv for that, or use 2 Seq instead of 2 Array if you
>want === to return true on the same values.

Is Seq vs Array the right distinction here? A Seq is immutable, so I
can't change its size, for instance, which is not what I want. I
just want [1,2] to be === to [1,2], or [1,2, \@x] to be equal to
[1,2, \@x] but !=== [1,2, \@y] -- eqv won't work in the latter case
(regardless of Seq vs. Array -- I didn't think it made a difference
here).

Actually, my previous example which Larry said was correct was:

$a=[1, 2, \@x];


$c=[1, 2, \@x];
$d=[1, 2, \@y];

$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, \@x and \@y are different refs

So $a, $c, and $d may all have the same *value* (or "snapshot", when
evaluated all the way down through nesting and references), i.e. they
might be eqv, but only $a and $c are === because they have the same
contents [unevaluated contents] and $d doesn't.

Which is what makes sense to me, but S03 says "[1,2]!===[1,2]". My
position is that even if they are different "objects", that
difference is fairly useless, and should therefore be hidden (same as
it is for objects that are strings).

>First of all, in Perl 6, there are no separate "arrays" and "array
>refs"; we simply have the 'Array' type, which is treated as a lump
>on its own.
>More generally, there are no "reference" types in Perl 6.

I thought there were, just not as conspicuously. There are
"captures" anyway, which are supposed to be like P5-refs, and beyond.
(However, I admit to being a bit fuzzy on exactly how Signatures and
Captures work -- if anyone could write an Exegesis on the subject, I
know I'm not the only one who would appreciate it.)

[...]


>The difference between === and eqv is that, if you have 2 symbols,
>$a and $b, and $a === $b returns true, then that result is
>guaranteed to be eternal if you don't assign to either symbol
>afterwards. For a mutable type like an Array, === returns false on
>2 containers because it can't guarantee that someone else holding
>another symbol for either container won't change its content, and so
>$a or $b could change after we made the === test, without us causing
>that to happen, and so for mutable types, === only returns true for
>2 aliases, because that is the most it can guarantee that they will
>be the same.

So, given mutable types, $a===$b if and only if $a=:=$b? That
doesn't sound right, otherwise === seems superfluous. The thing is
if $a=[1,2] and $b=[1,2], then arrays or not, nothing can change $a
or $b except by changing $a or $b. [Or aliases bound to same, of
course.] So there's no reason for $a===$b to be false. (If they
look the same, and they act the same, then they're ducks. Er, or
something.)

(Hoping the 'eternal' stuff hasn't thrown me off and resulted in my
completely misinterpreting what you were trying to say.)


-David

David Green

unread,
Aug 17, 2006, 2:43:13 AM8/17/06
to perl6-l...@perl.org
On 8/16/06, David Green wrote:
> $a=[1, 2, \@x];
> $c=[1, 2, \@x];
> $d=[1, 2, \@y];
>
> $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, \@x and \@y are different refs
>
>So $a, $c, and $d may all have the same *value* (or "snapshot", when
>evaluated all the way down through nesting and references), i.e.
>they might be eqv, but only $a and $c are === because they have the
>same contents [unevaluated contents] and $d doesn't.

OK, here's the counter-argument to my incessant ranting:

In the above example, $a and $c do "look" awfully similar, but
suppose we replace the anonymous arrays with named ones:

@X1=(1, 2, \@x);
@X2=(1, 2, \@x);

$a=\@X1;
$b=\@X2;

Now $a clearly does NOT === $b, because @X1 and @X2 are different
variables (that just coincidentally happen to share the same contents
at the moment). Replacing @X1 and @X2 with their anonymous
equivalents shouldn't suddenly change that.

[Well, anonymous object could have different rules, I suppose, but
it's no longer "obvious" that they should. Strings, for example, do
have special treatment to make different string-objects look the
same, but strings can't contain other variables, so it's easy to make
them act like plain values.]

However, it also follows that @X1 !=== @X2. There's no anonymous
reference hiding there, so why aren't @X1 and @X2 the same? (Well,
they just aren't!) So... probably what I wanted all along is just to
compare the contents of an array -- and === just isn't it. Hm.

=:= checks for same variable
=== checks for same object
eqv checks for same value

except that if the operands aren't objects, === will compare them as
values (like eqv). Or rather, if an item is a value (or an object
that ought to act like a value), just make sure its SKID (which ===
uses) compares in an appropriate value-like way.


-David

Darren Duncan

unread,
Aug 17, 2006, 3:00:17 AM8/17/06
to perl6-l...@perl.org
At 11:16 PM -0600 8/16/06, David Green wrote:
>On 8/15/06, Darren Duncan wrote:
>>At 2:51 PM -0600 8/15/06, David Green wrote:
>[...]
>>You are right, but we have both Seq and Array types, so depending
>>which one you use, you want either the === or eqv operators to do
>>what you want. There is no reason that === should say 2 Array are
>>equal; we have eqv for that, or use 2 Seq instead of 2 Array if you
>>want === to return true on the same values.
>
>Is Seq vs Array the right distinction here? A Seq is immutable, so
>I can't change its size, for instance, which is not what I want. I
>just want [1,2] to be === to [1,2], or [1,2, \@x] to be equal to
>[1,2, \@x] but !=== [1,2, \@y] -- eqv won't work in the latter case
>(regardless of Seq vs. Array -- I didn't think it made a difference
>here).

As a lead-in, I should say that Synopsis 3 has a good and complete
explanation of these matters and has had it for several weeks, in my
opinion.

Since you are wanting to compare two mutable Array, just use the eqv
operator, which will do everything you want in a terse and easy to
understand manner.

Generally speaking, the direct use of === is more for specialized
purposes, somewhat like the direct use of =:= is. If one can't tell
the difference between === and eqv, they most likely want snapshot
semantics anyway, and so might as well forget === exists, and just
use eqv everywhere.

There's no point arguing that === should deeply compare mutable types
when you already have eqv to do that. Continuing on like you appear
to be is like saying that the + operator should be useable to
concatenate two Str, when we have the ~ operator for that. Arguing
that === should deeply compare mutable types is like arguing that +
should contactenate two Str.

-- Darren Duncan

Markus Laire

unread,
Aug 17, 2006, 7:49:25 AM8/17/06
to perl6-l...@perl.org
On 8/17/06, Darren Duncan <dar...@darrenduncan.net> wrote:
> Generally speaking, the direct use of === is more for specialized
> purposes, somewhat like the direct use of =:= is. If one can't tell
> the difference between === and eqv, they most likely want snapshot
> semantics anyway, and so might as well forget === exists, and just
> use eqv everywhere.

For me === feels like it should be the operator with "easier"
semantics, i.e. the operator which perl-newbies would first want to
learn, so it feels like the semantics of === and eqv should be
swapped.

=== is a lot nearer to what many other languages uses for they
comparison than more cryptic eqv.

Also, == does "simpler" comparison than eq, so I feel that === should
also do "simpler" (to understand) comparison than eqv

--
Markus Laire

David Green

unread,
Aug 17, 2006, 1:26:37 PM8/17/06
to perl6-l...@perl.org
On 8/17/06, Darren Duncan wrote:
>At 11:16 PM -0600 8/16/06, David Green wrote:
>>I just want [1,2] to be === to [1,2], or [1,2, \@x] to be equal to
>>[1,2, \@x] but !=== [1,2, \@y] -- eqv won't work in the latter case
>>(regardless of Seq vs. Array -- I didn't think it made a difference
>>here).
[...]

>Since you are wanting to compare two mutable Array, just use the eqv
>operator, which will do everything you want in a terse and easy to
>understand manner.

No, look at the example I've been using. Two arrays (1, 2, \@x) and
(1, 2, \@y) clearly have different (unevaluated) contents. "eqv"
only tells me whether they have the same value (when @x and @y are
evaluated). That's a different question -- yes, it's the more common
question, but I think the comparison I want to make is just as
reasonable as ===, except there's no easy way to do it.


-David

David Green

unread,
Aug 17, 2006, 2:18:55 PM8/17/06
to perl6-l...@perl.org
On 8/16/06, David Green wrote:
> $a=[1, 2, \@x];
> $c=[1, 2, \@x];
> $d=[1, 2, \@y];
>
> $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, \@x and \@y are different refs
>
>So $a, $c, and $d may all have the same *value*
>(or "snapshot", when evaluated all the way down
>through nesting and references), i.e. they might
>be eqv, but only $a and $c are === because they
>have the same contents [unevaluated contents]
>and $d doesn't.

(Actually $a===$c above should be false.) Given
that === answers the question "are these things
the same object", what's the solution for my
original motivation of comparing two items for
their unevaluated contents? "Eqv" evaluates
everything (both references and nested
containers) down to immutable values; I want to
follow nested structures all the way down, but
not evaluate/deref any variable references.

For the one-dimensional $a and $c given above, I could do something like:
?all(@$a==@$c, grep {$^a === $^c} zip(@$a; @$c))

For multidimensional/nested arrays, I could check
that they're the same size with $a.shape eqv
$b.shape, but I believe grep (or map, etc.) work
only one-dimensionally. I don't think using
hyperoperators would work either, because $a
»===« $c would deref the contained @x before
applying ===, right?

Plus hyperops return a nested structure, and I'm
looking for a single bool -- I think hyperising
"all" around the whole result would work....
Hyperops also upgrade dimensions that don't match
between the RHS and LHS, which is not always what
you want.

So perhaps what I'm looking for is more syntactic
sugar for easily traversing nested data
structures in different ways.


-David

Larry Wall

unread,
Aug 17, 2006, 2:35:14 PM8/17/06
to perl6-l...@perl.org
On Thu, Aug 17, 2006 at 12:18:55PM -0600, David Green wrote:
: So perhaps what I'm looking for is more syntactic
: sugar for easily traversing nested data
: structures in different ways.

Quoth S03:

If that's not enough flexibility, there is also an C<eqv()> function
that can be passed additional information specifying how you want
canonical values to be generated before comparison. This gives
C<eqv()> the same kind of expressive power as a sort signature.

Larry

Mark J. Reed

unread,
Aug 17, 2006, 2:41:42 PM8/17/06
to David Green, perl6-l...@perl.org
On 8/17/06, David Green <david...@telus.net> wrote:
> > $a=[1, 2, \@x];
> > $c=[1, 2, \@x];
> > $d=[1, 2, \@y];
> >
> >So $a, $c, and $d may all have the same *value*
> >(or "snapshot", when evaluated all the way down
> >through nesting and references), i.e. they might
> >be eqv, but only $a and $c are === because they
> >have the same contents [unevaluated contents]
> >and $d doesn't.

In this case, it seems like [===] @$a, @$c would do what you want,
yes? It would return true, while [===] @$a,@$d would return false...

In the general case - well, I think the thread demonstrates that it's
hard to define a general case for what you want to do. Based on your
example, I assumed you wanted one-level dereferencing, regardless of
the contents. But it sounds like what you want is infinite
dereferencing as long as the referent is anonymous, and no
dereferencing if the referent is a named variable? That doesn't seem
like a common enough case to warrant sugar to me; what am I missing?

--
Mark J. Reed <mark...@mail.com>

Dave Whipp

unread,
Aug 17, 2006, 3:46:49 PM8/17/06
to perl6-l...@perl.org
David Green wrote:
>
>
> No, look at the example I've been using. Two arrays (1, 2, \@x) and (1,
> 2, \@y) clearly have different (unevaluated) contents. "eqv" only tells
> me whether they have the same value (when @x and @y are evaluated).
> That's a different question -- yes, it's the more common question, but I
> think the comparison I want to make is just as reasonable as ===, except
> there's no easy way to do it.


does "*$a === *$b" work? I.e. splat the two arrays into sequences, and
then do the immuable compare on those sequences.

Andrew Suffield

unread,
Aug 17, 2006, 8:31:53 PM8/17/06
to perl6-l...@perl.org
On Thu, Aug 17, 2006 at 12:00:17AM -0700, Darren Duncan wrote:
> As a lead-in, I should say that Synopsis 3 has a good and complete
> explanation of these matters and has had it for several weeks, in my
> opinion.
>
> Since you are wanting to compare two mutable Array, just use the eqv
> operator, which will do everything you want in a terse and easy to
> understand manner.

I'd just like to point out that S03 is back-arsewards here - it
explains === first, and then explains eqv in terms of ===. Since eqv
is the familiar thing people will want most of the time, and === is
the weird thing that isn't used very often, it would make far more
sense to explain them the other way around (and probably confuse less
people). Understanding === should not be a prerequisite for
understanding eqv.

Ben Morrow

unread,
Aug 17, 2006, 3:31:14 PM8/17/06
to perl6-l...@perl.org

Quoth mark...@mail.com ("Mark J. Reed"):

> On 8/17/06, David Green <david...@telus.net> wrote:
> > > $a=[1, 2, \@x];
> > > $c=[1, 2, \@x];
> > > $d=[1, 2, \@y];
> > >
> > >So $a, $c, and $d may all have the same *value*
> > >(or "snapshot", when evaluated all the way down
> > >through nesting and references), i.e. they might
> > >be eqv, but only $a and $c are === because they
> > >have the same contents [unevaluated contents]
> > >and $d doesn't.
>
> In this case, it seems like [===] @$a, @$c would do what you want,
> yes? It would return true, while [===] @$a,@$d would return false...
>
> In the general case - well, I think the thread demonstrates that it's
> hard to define a general case for what you want to do. Based on your
> example, I assumed you wanted one-level dereferencing, regardless of
> the contents. But it sounds like what you want is infinite
> dereferencing as long as the referent is anonymous, and no
> dereferencing if the referent is a named variable?

Surely that's a meaningless distinction? A named variable can become
anonymous if its name goes out of scope; an anon can be bound to a name.

Just to make sure I've got all this straight:

=:= compares names
=== compares containers
eqv compares values

So given an array @W,

my @X := @W; # @X =:= @W
my @Y = @W; # @Y === @W but @Y !=:= @W
my @Z = @W.clone; # @Z eqv @W but @Z !=== @W

? This seems like a useful set of distinctions to me...

<lurk>

Ben

--
The cosmos, at best, is like a rubbish heap scattered at random.
Heraclitus
benm...@tiscali.co.uk

Audrey Tang

unread,
Aug 17, 2006, 11:52:29 PM8/17/06
to Ben Morrow, perl6-l...@perl.org

在 2006/8/18 上午 3:31 時,Ben Morrow 寫到:

> Just to make sure I've got all this straight:
>
> =:= compares names
> === compares containers
> eqv compares values

=:= evaluates both sides as lvalue -- that's VAR() -- and compare
them with ===.
=== evaluates both sides as rvalue and, for container (mutable)
types, compares their pointer address.
eqv evaluates both sides as rvalue and, for container (mutable)
types, compares their content values.

None of the three coerces their arguments to concatenated List (aka
list flattening, aka slurpy context).

> So given an array @W,
>
> my @X := @W; # @X =:= @W
> my @Y = @W; # @Y === @W but @Y !=:= @W
> my @Z = @W.clone; # @Z eqv @W but @Z !=== @W

Your Array example would be correct with the $ sigil:

my $w = [1,2,3,4]; # Scalar containing Array
my $x := $w; # $x =:= $w
my $y = $w; # $y === $w but $y !=:= $w
my $z = $w.clone; # $z eqv $w but $z !=== $w

However, &infix:<=> when its left-hand side is an array, has an
different signature
(and indeed, different precedence) than when its left-hand side is a
scalar:

my $y = $w; # does not flatten $w
my @Y = @W; # does flatten @w, essentially doing a .clone
my @Z = @W.clone; # same as "my @Z = @W" really.

So the two assignments (@Y and @Z) above turns out to be the same
thing, and neither
will make "===" hold afterwards.

Cheers,
Audrey

PGP.sig
0 new messages