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

2006-07-13 Thread Darren Duncan

At 7:25 PM +0300 7/12/06, Yuval Kogman wrote:

Over at #perl6 we had a short discussion on =:=, ===, and ~~, mostly raised by
ajs's discussion on Str items and ===.



Coincidentally, I raised almost the same questions there a week 
earlier, and had a brief discussion with audreyt about it, though the 
answers that came out of it seemed rather different than what was in 
this thread so far, so I will share them.  See the following url:


http://colabti.de/irclogger/irclogger_log/perl6?date=2006-07-06,Thu&sel=376#l599

I will also quote the text as it was short, snipping out unrelated parts:

[ 11:29pm ] dduncan : slight change of topic, but I was wondering how 
.id works with non-trivial types

[ 11:29pm ] dduncan : eg, what does the .id of a Pair look like?
[ 11:29pm ] dduncan : I know that to users it shouldn't matter, but 
to people implementing composite types, it does

[ 11:30pm ] audreyt : dduncan: one possibility - could be just itself.
[ 11:33pm ] dduncan : one key thing I'm wondering about .id for 
immutable types is ... are they supposed to generate some neutral 
value like an integer, two of which can then be compared 
independently of the type definition, or will they contain references 
to the actual object all the time and that the object's class still 
needs to declare a === method which is invoked as needed?
[ 11:33pm ] dduncan : if it is the latter, I imagine that 
implementation will be simpler, at a possible cost of performance if 
the same comparison is done a lot

[ 11:34pm ] audreyt : dduncan: the latter
[ 11:34pm ] dduncan : okay, that answers my question

So, in the general case, it would seem best if the binary operator 
=== was just an ordinary method that each class provides, rather than 
requiring classes to defined a .id.  Or in addition to this to help 
with performance, a .id can exist anyway that optionally returns an 
appropriate hash of an object.


A default === would be defined in Object, which returns the same 
result as =:= returns; two objects are equivalent iff they are the 
same container.  A default .id defined in Object would simply return 
the same object it was invoked on.


Built-in immutable types, like Str and Int and Pair and Seq, would 
override that === such that they return true iff the two operands are 
containers of the same class and the two containers both hold 
appearances of the same (universally distinct) value.  This is 
determined by doing a deep comparison of the values themselves, as is 
appropriate.  (Internally to the type's implementation, a 
domain-appropriate hash of the value could optionally be generated at 
an appropriate time and be used to speed up === operations, with 
appropriate action taken if it isn't guaranteed that multiple 
distinct values won't become identical hash values.)  The .id could 
be overridden to return a simple number or string or binary for 
simpler types, and return the object itself otherwise.


Built-in mutable types, like Array or Hash, would not override the 
Object-defined ===, which is equivalent to =:=, nor the built-in .id, 
which returns the object itself.  This is reasonable in practice 
because the contents of those containers could be changed at any 
time, especially if the containers are aliased to multiple variables 
that are outside of the testing code's control.  The only thing that 
can be guaranteed to be constant over time is that whether or not an 
object is itself, as determined by =:=.  By contrast, if === were to 
do a deep copy with mutable types, the results could not be trusted 
to be repeatable because the moment after === returns, the 
container's value may have changed again, so actions done based on 
the === return value would be invalid if they assumed the value to 
still be the same at that time, such as if the mutable type was used 
as a hash key and was to be retrievable by its value.


User defined types can choose on their own whether to override === 
and/or .id or not, and they would use their own knowledge of their 
internal structures to do an appropriate deep comparison.  There is 
no need to try to generate some kind of unique numerical .id for 
arbitrarily complex objects.


One thing that can't be overridden is that === can only return true 
iff both operands are of the same class.  This includes undef, as 
each class has its own undef that is distinct from those of other 
classes.


So if this is the way that things worked, then it would be very easy 
to implement it for any kind of type.  And it would be very reliable 
to use any type as a hash key.


Note that, while the fact may be determinable by some other means, it 
may be useful to have an explicit meta-method for all types that says 
whether the type is immutable or mutable.  A user defined type saying 
that it is immutable is making a promise to the compiler that its 
objects won't change after they are created.


As for being able to tersely do deep comparisons of mutable types, I 
don't think that === is ap

Re: Another quick one: .as

2006-07-13 Thread Aaron Sherman
On Wed, 2006-07-12 at 17:52 -0700, Larry Wall wrote:
> On Wed, Jul 12, 2006 at 12:51:57PM -0400, Aaron Sherman wrote:
> : I would assume that all classes automatically define:
> : 
> :  multi submethod *infix: ($self: $?CLASS) { $self }
> 
> Hmm, "as" is really only intended for explicit type mutation (which
> can work either by role mixin or by new object construction).  It's
> not intended to give Perl a different "view" of an unmutated object.

Thanks. I think I got compile-time polymorphism confused with run-time
mutation. These are moose of vastly different colors.

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




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

2006-07-13 Thread Yuval Kogman
On Thu, Jul 13, 2006 at 00:55:30 -0700, Darren Duncan wrote:

> So, in the general case, it would seem best if the binary operator === was 
> just an ordinary method that each class provides, rather than requiring 
> classes to defined a .id.  Or 
> in addition to this to help with performance, a .id can exist anyway that 
> optionally returns an appropriate hash of an object.

But what is the benefit here?

Keying by object is a difficult topic. In Perl 5 you sometimes want
to key by refaddr (more often than not) because you are associating
new metadata with the instance, that does not belong inside the
instance.

On the other hand you also often want something like "$obj" to be
the key, if it can properly stringify, so that an object like a
currency:

my $x = Currency.new( code => "USD" );
my $y = Currency.new( code => "USD" );

$hash{$x} = 1;

say $hash{$y}; # 1

will DWIM. But this really depends on both the item being used,
*and* the way it is being used.

So I can see the value of making the second type of keying possible
and easy with an .id method (which at the very lowest level can
probably just emit e.g. a YAML representation of an object to ensure
uniqueness, if performance is *really* not an issue).

But this does not relate to equality, it's only useful for defining
it.

We were essentially questioning the reason === is specced to behave
as it currently does, because we feel that it's not very useful if
it's not clear cut that it should either *really* compare, or not
compare at all. And if it doesn't compare, we'd like a deep
comparison operator in S03.

> Built-in mutable types, like Array or Hash, would not override the 
> Object-defined ===, which is equivalent to =:=, nor the built-in .id, which 
> returns the object itself.  This 
> is reasonable in practice because the contents of those containers could be 
> changed at any time, especially if the containers are aliased to multiple 
> variables that are outside 
> of the testing code's control.  The only thing that can be guaranteed to be 
> constant over time is that whether or not an object is itself, as determined 
> by =:=.  By contrast, if 
> === were to do a deep copy with mutable types, the results could not be 
> trusted to be repeatable because the moment after === returns, the 
> container's value may have changed 
> again, so actions done based on the === return value would be invalid if they 
> assumed the value to still be the same at that time, such as if the mutable 
> type was used as a hash 
> key and was to be retrievable by its value.


The behavior for arrays is useless to me, because I already have
=:=. I can write a hybrid ===/=:= operator for very special cases,
but 99% of the time I want to ask "do these (arrays|hashes) contain
the same values *right now*?"

> User defined types can choose on their own whether to override === and/or .id 
> or not, and they would use their own knowledge of their internal structures 
> to do an appropriate 
> deep comparison.  There is no need to try to generate some kind of unique 
> numerical .id for arbitrarily complex objects.

That creates a mess - sometimes objects compare themselves based on
their value, and sometimes based on their containing slot. These are
very different semantics.


-- 
  Yuval Kogman <[EMAIL PROTECTED]>
http://nothingmuch.woobling.org  0xEBD27418



pgpxFsetaGrOi.pgp
Description: PGP signature


S29 demerge and API document plan

2006-07-13 Thread Aaron Sherman
Audrey has asked me to split S29 AKA Perl6/Spec/Functions.pod up due to
its rapidly expanding size. The strategy that she suggested is basically
what I'm leaning toward, but I wanted to get feedback (esp. from Larry
and other Synopsians).

I want to be clear, I'm not asking for help coming up with a way to do
this, just trying to see if I'm going to completely hose The Plan(tm).
Something like this could easily be a week-long thread, and I don't want
to go there unless I really have to.

"S29: Functions" will be an overview, and will contain a sectional
format as it does now, broken up by high-level modules. This isn't in
question, since three of us who have worked on it have found this to be
the best way to approach it, and it's not the best use of my time to go
re-writing the whole structure, anyway.

Each section will lead with a blurb about the module and a reference to
its API document.

For the most part, these sections will be populated with functions, but
method variants where there is a functional equivalent will only get a
passing mention and no signature. Method-only entries will not be
mentioned in this document, and instead will be moved out to the API
document specific to the module/class in question.

Modules which are very self-contained (e.g. Math::Trig) will JUST get a
blurb, suggesting that the reader peruse the appropriate API document.

Modules which have relatively generic OS or other non-core language
features may be abbreviated, and some functions may get little or no
mention. These details will be moved out to the API document for the
module in question.

Constants will be entirely in the API document, but will probably get a
short note in S29.

A "Compatibility" section will be added which will break all of the Perl
5 functions from perlfunc down into several categories:

  * As-is - the old usage is essentially unchanged (e.g. sprintf)
  * Altered - The new usage is functionally different, but similar
(or a subset, e.g. eval)
  * Name only - The new usage has almost nothing to do with the old
(e.g. each)
  * Compatibility - The old name is supported, but deprecated (e.g.
chr)
  * Unsupported - The old name is gone (e.g. waitpid)

If a function is not exported by default, it will also be noted in this
section.

In this way, even though S29 may not contain every function available to
Perl 6 programmers as a builtin, it will at least give Perl 5
programmers a sense of what happened to what they knew. The API
documents should probably be the more authoritative reference for
implementing P6 core libraries.

-- 
Aaron Sherman <[EMAIL PROTECTED]>
http://www.ajs.com/~ajs/
Mushroom Photography: http://mush.ajs.com/news/



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

2006-07-13 Thread Yuval Kogman
So, Larry assisted by Audrey explained the purpose of === vs eqv vs
=:=.

It makes sense now, but I still feel that as far as ergonomics go
this is not perfect. Then again, I trust that Larry's opinion is
probably better and at the very least more likely to be accepted
than mine ;-) [1]


So, this is the deal:


=== is for checking immutable equality. This is a bit nasty to
explain.

eqv is going to be deep comparison, like most of us thought '==='
was going to be (I had initially thought that eqv was renamed to ===
when === started popping up).

=:= is something completely different, but will be easy to explain
in a moment.


What it means for something to be immutable can be demonstrated
rather easily here:

my $x = 10;
my $y = $x;

$x === $y; # true

$y++:

$x === $y; # false

Since numbers (and also strings) are "simple" values, that are not
modified in place (at least not explicitly), but are instead copied
and modified or just replaced when you change them, the .id of the
thing inside $x and $y is bound to the value.

You could rationalize this such that .id is the same if and only if
it doesn't actually matter (and never will matter) if the value is
in the same chunk of memory or a separate one, as far as the runtime
is concerned.

Arrays and hashes, and other complex types can, on the other hand
have parts of them transformed without first cloning everything
(which is precisely why they're useful).

The underlying idea is that === can be used to test if two values are
*always* going to be the same (if they're container gets a different
value in it that does not mean that they are no longer the same).

eqv, on the other hand is used to test whether or not two values are
the same right now, without making any implications as to what their
values will be later on, since they may mutate. This is deceivingly
like == and eq if you assume that numbers and strings are changed,
instead of replaced.

Lastly, =:= is really variable($x) === variable($y) - that is,
whether or not the container is the same value or not. This
basically checks whether either $x or $y was at some point bound to
the other, or in specific situations whether they're tied to the
same representation even if they are different containers.

Overridding .id is useful for when you want to imply that two items
are exactly the same and will always be the same and will never
change as far as their comparison is concerned (both eqv and ===
will always be true), even if the default implementation of === does
not return true due to technical details. === can be thought of as
.id eqv .id.

I hope this clears things up, and thanks again, Larry and Audrey, for
clearing this up.

I'd like for someone with better english skills to summarize into an
S03 patch please. It needs to be much shorter =)

[1] My preferred ergonomics:

1. eqv goes away
2. what was eqv is renamed to ===
3. === becomes =:=, which has a "constant" feel to it
4. =:= is rarely useful IMHO, so you can just type
variable($x) =:= variable($y)

Ciao

-- 
  Yuval Kogman <[EMAIL PROTECTED]>
http://nothingmuch.woobling.org  0xEBD27418



pgpU0Qe5CPlhQ.pgp
Description: PGP signature


Run time dispatch on ~~

2006-07-13 Thread Aaron Sherman
I'm told that I did a terrible job of making my point in the === thread,
and nothingmuch asked me on IRC to re-state my concerns. I'll do so
briefly, and then give examples. Please do have a look at the examples,
just in case I'm not clear.

Overview:

~~ is great. It matches on all kinds of useful right-hand-sides like
regexes, strings, methods, your neighbor's kids, you-name-it.

The only problem that I have is ~~ matching against an unknown type
(Any~~Any). In this case, the programmer cannot know what it is that
they're getting themselves into, and for the life of me, I can't see why
Perl would do anything other than an only slightly smart comparison
there, since that's obviously what the programmer had in mind.

However, S03 specs that ~~ will do a run-time dispatch based on the type
of that value at the time. Matching Arrays (@~~@) is just a
hyperoperated case of the same problem, except for the case where the
array on the right-hand-side can be typed at compile-time or is a list
that can be coerced painlessly into such a typed array. Then there's no
dispatch at run-time.

Solution:

Ok, so first let me re-propose my solution: Any~~Any and @~~@ are
compile-time dispatched to =~= and >>=~=<< respectively (no, I'm not
married to the name, and perhaps eqv is better for this, I don't know),
which has some smarts about comparing values in meaningful ways, and
which programmers know to override if they really need special matching
semantics, but basically is just a very slightly smarter ===. Regexes
are compared, not executed. Code is compared, not executed.

Examples:

Now, let's look at some of the good that ~~ does for us:

$a ~~ "Some string" # sameness
$a ~~ 5 # sameness
$a ~~ ->{...}   # test
$a ~~ /.../ # regex matching

That's great, and we don't want to mess with any of it.

But, then we have:

$a ~~ $b# uh... something

We can't even say what it does, much less why it's useful. It does
"match" whatever that is. Sure, it's great for implementing your own ~~,
but that's about it.

The even worse:

@a ~~ @b# uh... lots of something

looks like array comparison to the casually misinformed user, but is
actually a run-time, hyperized vector dispatch...

Now, I do think people will want to:

@a ~~ ( /^\d+$/, /^\w+$/, /^\s+$/ )

but we can coerce that into a typed array at compile time, so there's no
problem.

Going with my suggestion would mean that ~~ is still very powerful, just
not opaque. You would have to ask for it to activate a particular
superpower by giving it a right-hand-side that has a type, or expect a
fairly mundane comparison to be performed.

The _security_ implications will likely get sorted out, but I still
forsee some major end-user bogglage when $a~~$b is true, even though
they have no relationship to each other that was obvious to the
programmer who wrote the statement.

Keep in mind that if you have an Any and you want to match against it
smartly, you can always request your poison:

$a ~~ ($b as Regex)

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




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

2006-07-13 Thread Larry Wall
On Thu, Jul 13, 2006 at 09:32:08PM +0300, Yuval Kogman wrote:
: [1] My preferred ergonomics:
: 
:   1. eqv goes away
:   2. what was eqv is renamed to ===
:   3. === becomes =:=, which has a "constant" feel to it
:   4. =:= is rarely useful IMHO, so you can just type
:   variable($x) =:= variable($y)

It is important for eqv to be alphabetic so we can have the functional
form take an optional signature parameter to specify what is compared.

eqv($a,$b, :($x,$y))

Think of this as the same as the sort specifier that says what to sort on,
only we're only interested in eqv-ness rather than cmp-ness.

In fact, cmp (or something like it) also wants to take a third parameter:

leg($a,$b, :($x is num,$y is rev));

and then sort is just done with the same signature:

sort :($x is num,$y is rev), @foo;

or some such, however you want to canonicalize the records.
The sort routine can decide whether it'll be more efficient to do
various transforms or maneuvers based on the declarative syntax of
the signature.

Then $a eqv $b and $a leg $b both just default to a signature that selects
everything.

Larry


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

2006-07-13 Thread Larry Wall
On Thu, Jul 13, 2006 at 12:50:19PM -0700, Larry Wall wrote:
: Then $a eqv $b and $a leg $b both just default to a signature that selects
: everything.

Though arguably P5's string-forcing semantics should be C and the
polymorphic semantics should probably be C.

Larry


Re: Run time dispatch on ~~

2006-07-13 Thread Yuval Kogman
On Thu, Jul 13, 2006 at 15:44:33 -0400, Aaron Sherman wrote:

> Now, let's look at some of the good that ~~ does for us:
> 
>   $a ~~ "Some string" # sameness
>   $a ~~ 5 # sameness
> $a ~~ ->{...}   # test
> $a ~~ /.../ # regex matching
> 
> That's great, and we don't want to mess with any of it.
> 
> But, then we have:
> 
>   $a ~~ $b# uh... something


One compelling reason to have them behave exactly the same is to
allow refactoring.

If i'm using the same pattern on several inputs i'd like to maybe
delegate this to a helper sub that will actually run the ~~ for me,
in some way, and i'd like 100% compatibility.

Also, sometimes i am matching on behalf of my caller, this is very
common in dispatch algorithms, or things like tree visitors:

my @list = $tree.filter_children( $match ); # very generic and useful


-- 
  Yuval Kogman <[EMAIL PROTECTED]>
http://nothingmuch.woobling.org  0xEBD27418



pgp8KEQiTHBTj.pgp
Description: PGP signature


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

2006-07-13 Thread Darren Duncan

At 5:36 PM +0300 7/13/06, Yuval Kogman wrote:
 > User defined types can choose on their own whether to override 
=== and/or .id or not, and they would use their own knowledge of 
their internal structures to do an appropriate
 deep comparison.  There is no need to try to generate some kind of 
unique numerical .id for arbitrarily complex objects.


That creates a mess - sometimes objects compare themselves based on
their value, and sometimes based on their containing slot. These are
very different semantics.


The idea here is that === is a test for deep-as-possible immutable 
equality.  If the user-defined object is immutable, then === does a 
full deep compare.  If the object is mutable, then === goes only as 
deep as can be guaranteed will never change, which is usually what 
=:= looks at and no further.  There is no mess at all, the comparing 
by value is related to the immutability, and all objects of the same 
class would be the same in that respect.  Incidentally, your Currency 
example would likely be an immutable type. -- Darren Duncan


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

2006-07-13 Thread David Green

On 7/13/06, Yuval Kogman wrote:

So, Larry assisted by Audrey explained the purpose of === vs eqv vs =:=.
It makes sense now, but I still feel that as far as ergonomics go 
this is not perfect.


I think I understand it... (my only quibble with the syntax is that 
=== and eqv look like spin-offs of == and eq, but I don't know what 
to suggest instead (we're running short of combinations of = and : !))


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


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



Examples:

  @x=;
  @y=;

  $a=[1, 2, [EMAIL PROTECTED];
  $b:=$a;
  $c=[1, 2, [EMAIL PROTECTED];
  $d=[1, 2, [EMAIL PROTECTED];


$a =:= $b;  #true, same variable with two names
$a === $b;  #true   _/ $b just another name for $a,
$a eqv $b;  #true\ so comparable at all levels

$a =:= $c;  #false, different variables
$a === $c;  #true, same elements make up $a and $c
$a eqv $c;  #true, same elements therefore same values

$a =:= $d;  #false, different variables
$a === $d;  #false, [EMAIL PROTECTED] and [EMAIL PROTECTED] are 
different refs
$a eqv $d;  #true, values of @x and @y happen to be the same


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


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


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



-David


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

2006-07-13 Thread Jonathan Lang

David Green wrote:

I think I understand it... (my only quibble with the syntax is that
=== and eqv look like spin-offs of == and eq, but I don't know what
to suggest instead (we're running short of combinations of = and : !))


Agreed.


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


Apparently, there are _four_ basic kinds of comparison: the ones
mentioned above, and == (I believe that eq works enough like == that
whatever can be said about one in relation to ===, =:=, or eqv can be
said about the other).  I'd be quite interested in an expansion of
David's example to demonstrate how == differs from the others.

--
Jonathan "Dataweaver" Lang


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

2006-07-13 Thread Yuval Kogman
On Thu, Jul 13, 2006 at 12:50:19 -0700, Larry Wall wrote:
> On Thu, Jul 13, 2006 at 09:32:08PM +0300, Yuval Kogman wrote:
> : [1] My preferred ergonomics:
> : 
> : 1. eqv goes away
> : 2. what was eqv is renamed to ===
> : 3. === becomes =:=, which has a "constant" feel to it
> : 4. =:= is rarely useful IMHO, so you can just type
> : variable($x) =:= variable($y)
> 
> It is important for eqv to be alphabetic so we can have the functional
> form take an optional signature parameter to specify what is compared.

There's no contradiction, === could be an alias to eqv ;-)

-- 
  Yuval Kogman <[EMAIL PROTECTED]>
http://nothingmuch.woobling.org  0xEBD27418



pgpPDRBxXCeip.pgp
Description: PGP signature


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

2006-07-13 Thread Yuval Kogman
On Thu, Jul 13, 2006 at 21:55:15 -0700, Jonathan Lang wrote:

> Apparently, there are _four_ basic kinds of comparison: the ones
> mentioned above, and == (I believe that eq works enough like == that
> whatever can be said about one in relation to ===, =:=, or eqv can be
> said about the other).  I'd be quite interested in an expansion of
> David's example to demonstrate how == differs from the others.

sub &infix:<==> ( Any $x, Any $y ) { 
+$x === +$y; # propagate coercion failure warnings to caller
}

sub &infix: ( Any $x, Any $y ) { 
~$x === ~$y
}


-- 
  Yuval Kogman <[EMAIL PROTECTED]>
http://nothingmuch.woobling.org  0xEBD27418



pgp3B4GnByYFK.pgp
Description: PGP signature


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

2006-07-13 Thread Jonathan Lang

Yuval Kogman wrote:

Jonathan Lang wrote:
> Apparently, there are _four_ basic kinds of comparison: the ones
> mentioned above, and == (I believe that eq works enough like == that
> whatever can be said about one in relation to ===, =:=, or eqv can be
> said about the other).  I'd be quite interested in an expansion of
> David's example to demonstrate how == differs from the others.

sub &infix:<==> ( Any $x, Any $y ) {
+$x === +$y; # propagate coercion failure warnings to caller
}

sub &infix: ( Any $x, Any $y ) {
~$x === ~$y
}


So the purpose of === is to provide a means of comparison that doesn't
implicitly coerce its arguments to a particular type?

--
Jonathan "Dataweaver" Lang


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

2006-07-13 Thread Darren Duncan

At 10:36 PM -0700 7/13/06, Jonathan Lang wrote:

So the purpose of === is to provide a means of comparison that doesn't
implicitly coerce its arguments to a particular type?


Yes, absolutely.  The === takes 2 arguments exactly as they are, 
without changing anything, and says if they are two appearances of 
the same value.  It would always return false if the 2 arguments are 
of different declared types.  And if they are of the same types, then 
no coersion is necessary in order to compare them for equality.


Now, I didn't see them yet anywhere in Synopsis 3, but I strongly 
recommend having negated versions of all these various types of 
equality tests.  Eg, !== for ===, nev for eqv, etc.  They would be 
used very frequently, I believe (and I have even tried to do so), and 
of course we get the nice parity.


-- Darren Duncan


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

2006-07-13 Thread Darren Duncan
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