develooper Front page | perl.perl6.language | Postings from July 2006

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

Thread Previous | Thread Next
Darren Duncan
July 13, 2006 00:56
Re: ===, =:=, ~~, eq and == revisited (blame ajs!)
Message ID:
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:,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 

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 

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

-- Darren Duncan

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About