hphp/hack/doc/HIPs/equality_and_identity.md
Title: Equality, Identity, and Comparisons
Start Date: June 24 2020
Status: Draft
Unify == and ===, introduce sane alternatives for classes that need to use
behaviour similar to the old versions.
Hack has two main comparison operators == and ===. They're individually
comprised of behaviours both good and bad, and combine to a muddied, confusing,
and overall broken experience. == does coercing value equality, including on
objects, and compares arrays (sometimes unorderedly). === does pointer equality
checks on objects (including collections), and breaks some invariants for
reactive and pure code.
We'd like to simplify and correct the mistakes of the previous design
===
===, requiring identical internal ordering.==
===== for keys and == for values, ignoring order for dicts/darrays/keysets==, ignoring order for Map/Set<=, >=: Use == under the hood. No === variant.is_same_obj($a, $b) that does a pointer check
IIdentityTestable (name to be bikeshed).is_same_obj is free standing or works as $a→isSame($b) to be bikeshed
IEquatable
== or does it do something like $a→eq($b)
IEquatable== works as follows
IEquatable means can use ==, do we return false or throw when not present?IEquatable, and pointer equality on two of them is always false (or throws?).
resource and NaN? Other edge cases?
NaN !== Nan but vec[NAN] === vec[NAN]=== doesn’t exist<=,>=, etc inherit the changes to ==
IEquatable objects comparable this way? I expect not.pure/rx function requires them to be IEquatableN/A
Mostly still open questions above or below. Did I miss any?
What the typing rules of == under this proposal? Is it still a function that takes two values of type mixed?
TODO once we get more consensus about the open questions above
TODO
It's a ton of work. Probably not HAM level, but definitely a major project from the HF perspective
TODO
Note rust's ord, eq, partial ord, and partial eq. Rust (which took these ideas from Haskell) only allows you to compare values that implement these traits (typeclasses in Haskell).
For opt-in structural equality, what if I have a non-opted-in parent class? By opting in do I also opt it's fields in to being inspected? What about traits?
Should switches always use pointer equality on objects? This seems very relevant to enum classes.
How do function pointers work? And are you guaranteed to get the same pointer for two different calls
Does structural equality on well-formed IEquatable classes always work?
class ListNode implements IEquatable {
public function __construct(
public int $val,
public ?ListNode $prev = null,
public ?ListNode $next = null,
) {}
}
function compare_nodes(): void {
// Build a linked list [1, 2].
$n = new ListNode(1);
$n2 = new ListNode(2, $n);
$n->next = $n2;
// What value does $b have?
$b = $n == $n2;
}
The obvious recursive function for structural equality would loop infinitely on $n == $n2.
I think this is mostly N/A? Unless we want to reuse === for something?