[RFC] User-defined object comparison

php.internals

Rudolf Theunissen

8 years ago
Hi everyone, This is an RFC that is based on previous discussions here: https://externals.io/message/102337 RFC: https://wiki.php.net/rfc/object-comparison The implementation is tested and appears to be working as expected. :) - Rudi Theunissen

Net Mo

8 years ago
some ideas and concerns: - I would like to see this in an extension first, i think it's perfectly doable and people can test it before merging to core - would be nice if compareTo and equals were used only if left operand and right operand used the same comparator function. In other words, $a == $b must not work if $a->__equals and $b->__equals are two different functions - otherwise RFC should specify the precedence. if $left operand and $right operand both have the magic methods, it will call $left->__magic($right), otherwise, if only the right one has the handler? what if the right one has compareTo and the left has only equal? you probably should add a table that explains which method is called depending in the availability of the two magic methods in the operands. - I'd introduce a debug mode that forces php to call both $left->__equals($right) and $right->__equals($left) so that symmetry is guaranteed by design. You could do that when "assertions" are active. gl

Rudolf Theunissen

8 years ago
> I would like to see this in an extension first, i think it's perfectly
doable and people can test it before merging to core Actually not sure this can be done as an extension because it changes zend_operators and introduces a new handler to make it all work.
> Would be nice if compareTo and equals were used only if left operand and
right operand used the same comparator function. In other words, $a == $b must not work if $a->__equals and $b->__equals are two different functions So effectively it means we only call __equals if both sides are instances of the same class?
> If $left operand and $right operand both have the magic methods, it will
call $left->__magic($right), otherwise, if only the right one has the handler? What if the right one has compareTo and the left has only equal? you probably should add a table that explains which method is called depending in the availability of the two magic methods in the operands. Good idea. :) In brief, as it's implemented right now, the LHS takes precedence and the RHS will be called if it's the only one that implements the operation. I'll write some more tests for these cases and build that table for the RFC.
> I'd introduce a debug mode that forces php to call both
$left->__equals($right) and $right->__equals($left) so that symmetry is guaranteed by design. If we want to guarantee symmetry by design, we have to either compare both sides or only compare if instances of the same class, or document that comparison should be implemented such that a > b == b < a, etc. I'm not convinced that a double comparison outweighs the responsibility on the user to be sensible. On Tue, 26 Jun 2018 at 21:04, Wes <netmo.php@gmail.com> wrote:

Net Mo

8 years ago
not some class, only same comparator function. e.g. this is ok, as __equals is the same for both classes trait X{ function __equals($o){ ... } } class A{ use X; } class B{ use X; } assert((new A) == (new B));

Rowan Collins

8 years ago
On 27 June 2018 at 14:30, Wes <netmo.php@gmail.com> wrote:
> not some class, only same comparator function. e.g. this is ok, as __equals > is the same for both classes > trait X{ function __equals($o){ ... } } > class A{ use X; } > class B{ use X; } > assert((new A) == (new B)); >
What does "the same function" mean, though? The same text? The same entry in memory? In this example, the Trait will be copied into the class at compile time, so is not "the same function" in terms of internal representation. It may not even have the same code, since the magic contant __CLASS__ will be compiled to 'A' or 'B', never 'X'. Comparing by text doesn't seem that sensible; you could easily have two objects with "__compareTo($other) { return $this->value <=> $other-> value ; }" but that doesn't mean they should be comparable. The only meaningful constraint you could put on it is either "both objects are of the same class", or assert($other instance self) - i.e. compare against the same class or a sub-class. I think it's more straight-froward to always call the handler, and let the user decide which comparisons are computable. Regards,
-- Rowan Collins [IMSoP]

Michał Brzuchalski

8 years ago
śr., 27 cze 2018 o 03:29 Rudolf Theunissen <rudolf.theunissen@gmail.com> napisał(a):
> > I would like to see this in an extension first, i think it's perfectly > doable and people can test it before merging to core > >
It was possible in Sara's extension[1], so maybe now also? Take a look.
> Actually not sure this can be done as an extension because it changes > zend_operators and introduces a new handler to make it all work. > > > Would be nice if compareTo and equals were used only if left operand and > right operand used the same comparator function. > In other words, $a == $b must not work if $a->__equals and $b->__equals are > two different functions > > So effectively it means we only call __equals if both sides are instances > of the same class? > > > If $left operand and $right operand both have the magic methods, it will > call $left->__magic($right), otherwise, if only the right one has the > handler? What if the right one has compareTo and the left has only equal? > you probably should add a table that explains which method is called > depending in the availability of the two magic methods in the operands. > > Good idea. :) In brief, as it's implemented right now, the LHS takes > precedence and the RHS will be called if it's the only one that implements > the operation. I'll write some more tests for these cases and build that > table for the RFC. > > > I'd introduce a debug mode that forces php to call both > $left->__equals($right) and $right->__equals($left) so that symmetry is > guaranteed by design. > > If we want to guarantee symmetry by design, we have to either compare both > sides or only compare if instances of the same class, or document that > comparison should be implemented such that a > b == b < a, etc. I'm not > convinced that a double comparison outweighs the responsibility on the user > to be sensible. > > On Tue, 26 Jun 2018 at 21:04, Wes <netmo.php@gmail.com> wrote: > > > some ideas and concerns: > > > > - I would like to see this in an extension first, i think it's perfectly > > doable and people can test it before merging to core > > > > - would be nice if compareTo and equals were used only if left operand > and > > right operand used the same comparator function. > > In other words, $a == $b must not work if $a->__equals and $b->__equals > > are two different functions > > > > - otherwise RFC should specify the precedence. if $left operand and > $right > > operand both have the magic methods, it will call $left->__magic($right), > > otherwise, if only the right one has the handler? > > what if the right one has compareTo and the left has only equal? you > > probably should add a table that explains which method is called > depending > > in the availability of the two magic methods in the operands. > > > > - I'd introduce a debug mode that forces php to call both > > $left->__equals($right) and $right->__equals($left) so that symmetry is > > guaranteed by design. You could do that when "assertions" are active. > > > > gl > > >
[1] https://github.com/php/pecl-php-operator/blob/master/operator.c
-- regards / pozdrawiam, -- Michał Brzuchalski about.me/brzuchal brzuchalski.com

Michał Brzuchalski

8 years ago
śr., 27 cze 2018 o 16:55 Michał Brzuchalski <michal@brzuchalski.com> napisał(a):
> > > śr., 27 cze 2018 o 03:29 Rudolf Theunissen <rudolf.theunissen@gmail.com> > napisał(a): > >> > I would like to see this in an extension first, i think it's perfectly >> doable and people can test it before merging to core >> >> > It was possible in Sara's extension[1], so maybe now also? Take a look. > > > >> Actually not sure this can be done as an extension because it changes >> zend_operators and introduces a new handler to make it all work. >> >> > Would be nice if compareTo and equals were used only if left operand and >> right operand used the same comparator function. >> In other words, $a == $b must not work if $a->__equals and $b->__equals >> are >> two different functions >> >> So effectively it means we only call __equals if both sides are instances >> of the same class? >> >> > If $left operand and $right operand both have the magic methods, it will >> call $left->__magic($right), otherwise, if only the right one has the >> handler? What if the right one has compareTo and the left has only equal? >> you probably should add a table that explains which method is called >> depending in the availability of the two magic methods in the operands. >> >> Good idea. :) In brief, as it's implemented right now, the LHS takes >> precedence and the RHS will be called if it's the only one that implements >> the operation. I'll write some more tests for these cases and build that >> table for the RFC. >> >> > I'd introduce a debug mode that forces php to call both >> $left->__equals($right) and $right->__equals($left) so that symmetry is >> guaranteed by design. >> >> If we want to guarantee symmetry by design, we have to either compare both >> sides or only compare if instances of the same class, or document that >> comparison should be implemented such that a > b == b < a, etc. I'm not >> convinced that a double comparison outweighs the responsibility on the >> user >> to be sensible. >> >> On Tue, 26 Jun 2018 at 21:04, Wes <netmo.php@gmail.com> wrote: >> >> > some ideas and concerns: >> > >> > - I would like to see this in an extension first, i think it's perfectly >> > doable and people can test it before merging to core >> > >> > - would be nice if compareTo and equals were used only if left operand >> and >> > right operand used the same comparator function. >> > In other words, $a == $b must not work if $a->__equals and $b->__equals >> > are two different functions >> > >> > - otherwise RFC should specify the precedence. if $left operand and >> $right >> > operand both have the magic methods, it will call >> $left->__magic($right), >> > otherwise, if only the right one has the handler? >> > what if the right one has compareTo and the left has only equal? you >> > probably should add a table that explains which method is called >> depending >> > in the availability of the two magic methods in the operands. >> > >> > - I'd introduce a debug mode that forces php to call both >> > $left->__equals($right) and $right->__equals($left) so that symmetry is >> > guaranteed by design. You could do that when "assertions" are active. >> > >> > gl >> > >> > > [1] https://github.com/php/pecl-php-operator/blob/master/operator.c > -- > regards / pozdrawiam, > -- > Michał Brzuchalski > about.me/brzuchal > brzuchalski.com >
There is also one more thing I can think of. If __equals and __compareTo methods don't have any restrictions for $other parameter typehint then I'll be able to declare Foo { public function __compareTo(int $other): int {} } and will get some error on new Foo() == new DateTime('now'); Right?
-- regards / pozdrawiam, -- Michał Brzuchalski about.me/brzuchal brzuchalski.com

Rowan Collins

8 years ago
On 27 June 2018 at 16:24, Michał Brzuchalski <michal@brzuchalski.com> wrote:
> There is also one more thing I can think of. If __equals and __compareTo > methods > don't have any restrictions for $other parameter typehint then I'll be able > to declare > Foo { > public function __compareTo(int $other): int {} > } > and will get some error on > new Foo() == new DateTime('now'); >
This can already happen with other magic methods. For instance: class A { public function __set(int $foo, int $bar) {} } $a = new A; $a->test = 42; # TypeError: Argument 1 passed to A::__set() must be of the type int, string given As long as the implementation correctly unwinds the stack when a Throwable is encountered (__toString *can't* cope with this, and bails out the engine), I don't think this is a problem. Regards,
-- Rowan Collins [IMSoP]

Chase Peeler

8 years ago
> > > > If $left operand and $right operand both have the magic methods, it will > call $left->__magic($right), otherwise, if only the right one has the > handler? What if the right one has compareTo and the left has only equal? > you probably should add a table that explains which method is called > depending in the availability of the two magic methods in the operands. > > I think $left == $right => $left->__equals($right) makes perfect sense.
$left dictates fallbacks, since $left is the one invoking the method. If $left doesn't have __equals, then it uses __compareTo... if it doesn't have either, it falls back to the original way. Bottom line, the existence or non-existence of either method on the right side doesn't matter. As with all type juggling, you run the risk that ($a == $b) !== ($b == $a). The other option would just be to force both objects to define at least the __compareTo method, and if one of them doesn't, it falls back to the old way. I woudn't go as far as requiring they be the same functions though... existence should be good enough. Maybe throw a warning if used for classes of different types or where the methods are different - but if I have class Apple and class Orange, and want to compare them, I should be able to do so! Has implementing this using an interface? Just like ArrayAccess defines methods that allow object to be referenced like an array, Comparable could provide methods (equals and comparesTo) that would override the comparison operators. Personally, I like magic methods, so I'm good with the RFC as-is.
-- -- Chase chasepeeler@gmail.com

Stas Malyshev

8 years ago
Hi!
> In other words, $a == $b must not work if $a->__equals and $b->__equals are > two different functions > > So effectively it means we only call __equals if both sides are instances > of the same class?
We can just define that == calls __equals on the left. That's, for example, what Python does. This would produce a weird consequence of $a == $b and $b == $a not being the same, but that's what you get for overloading operators. That's why overloading operators is not always the best idea, because of disconnect between perceived semantics (math equality operator, which is symmetric, reflexive and transitive) and actual semantic (which is not guaranteed to have any of the math equality properties). In any case, "the same class" would be too restrictive, as there's inheritance, so we should support LSP. But then again, if $a and $b are in different places on inheritance hierarchy, we can can non-symmetric operator. This is kinda deep problem that is not really working well in most Java code, for example. See: https://www.artima.com/pins1ed/object-equality.html (for reference, Martin Odersky is the guy who did Java generics, and designed Scala, so he knows a quite bit about OO things :)
-- Stas Malyshev smalyshev@gmail.com

Levi Morrison

8 years ago
On Tue, Jun 26, 2018 at 5:50 PM Rudolf Theunissen <rudolf.theunissen@gmail.com> wrote:
> > Hi everyone, > > This is an RFC that is based on previous discussions here: > https://externals.io/message/102337 > > RFC: https://wiki.php.net/rfc/object-comparison > > The implementation is tested and appears to be working as expected. :)
I had some off-list contact with Rudi and generally have agreed with these changes. However, there may be some value in following Python's lead. In Python 2 they had a `__cmp__` magic method and in Python 3 they removed it and added all of these: __lt__ __le__ __eq__ __ne__ __gt__ __ge__ This permits things such as NumPy to overload < to do an element-wise comparison of the members; something like this: np.array([1, 3, 5, 7]) < np.array([2, 1, 6, 6]) // evaluates to np.array([true, false, true, false) If we pursue this Pythonic route then we would also need methods for + - * / % etc. I do not want to derail the conversation too much, but it does seem opportune to discuss operator overloading more generally.

Levi Morrison

8 years ago
On Wed, Jun 27, 2018 at 12:24 PM Levi Morrison <levim@php.net> wrote:
> > On Tue, Jun 26, 2018 at 5:50 PM Rudolf Theunissen > <rudolf.theunissen@gmail.com> wrote: > > > > Hi everyone, > > > > This is an RFC that is based on previous discussions here: > > https://externals.io/message/102337 > > > > RFC: https://wiki.php.net/rfc/object-comparison > > > > The implementation is tested and appears to be working as expected. :) > > I had some off-list contact with Rudi and generally have agreed with > these changes. > > However, there may be some value in following Python's lead. In Python > 2 they had a `__cmp__` magic method and in Python 3 they removed it > and added all of these: > > __lt__ > __le__ > __eq__ > __ne__ > __gt__ > __ge__ > > This permits things such as NumPy to overload < to do an element-wise > comparison of the members; something like this: > > np.array([1, 3, 5, 7]) < np.array([2, 1, 6, 6]) > // evaluates to np.array([true, false, true, false) > > If we pursue this Pythonic route then we would also need methods for + > - * / % etc. I do not want to derail the conversation too much, but it > does seem opportune to discuss operator overloading more generally.
We would still need `__compareTo` if we did operator overloading because we have the `<=>` operator. Rudi has pointed out that because of this we should be able to overload individual operators at a later point without backwards compatibility issues if we so choose. I think this is true if we do not constrain the return types. In summary, I propose that return type constraints should be removed which will allow us to pursue specific operator overloading at a later point if we desire; an author can always add `: bool` or `: int` to their own methods if they so desire.

Rudolf Theunissen

8 years ago
> > In summary, I propose that return type constraints should be removed > which will allow us to pursue specific operator overloading at a later > point if we desire
There are no return types or parameter types. The only requirement is that the function is public and not static. On Wed, 27 Jun 2018 at 15:21, Levi Morrison <levim@php.net> wrote:

Rudolf Theunissen

8 years ago
Hi everyone, I've made some changes to the RFC and the implementation today to explain some of the edge cases and combined behaviour better. There are some issues towards the bottom of the RFC that I would really like some opinions on. They all have decisions made but are not concrete, so I'd like to know if anyone has strong opinions on them before they are considered a final part of the RFC. I'm happy with the current state but I'm very open to changing those decisions if there's a good enough reason to. See https://wiki.php.net/rfc/object-comparison#open_issues Thank you On Wed, 27 Jun 2018 at 18:53, Rudolf Theunissen <rudolf.theunissen@gmail.com> wrote:

Larry Garfield

8 years ago
On Wednesday, June 27, 2018 5:58:29 PM CDT Rudolf Theunissen wrote:
> Hi everyone, > > I've made some changes to the RFC and the implementation today to explain > some of the edge cases and combined behaviour better. > > There are some issues towards the bottom of the RFC that I would really > like some opinions on. They all have decisions made but are not concrete, > so I'd like to know if anyone has strong opinions on them before they are > considered a final part of the RFC. I'm happy with the current state but > I'm very open to changing those decisions if there's a good enough reason > to. > > See https://wiki.php.net/rfc/object-comparison#open_issues > > Thank you
Overall, I like. Regarding what is legal to compare to, it seems useful to leverage the optional type hint. So given: class Foo { public function __compareTo(Foo $other) {} } class Bar extends Foo { public function __compareTo(Bar $other) {} } In this case, the order of checking to see what method to call will also check for type compatibility. That is, $f < $b checks Foo::__compareTo(), finds it doesn't match, and so calls Bar::__compareTo() instead, which does. "However, because magic methods aren't inherited" - Wait, they're not? Are you certain of that? Because 3v4l.org says they are: https://3v4l.org/P6Hlq I don't understand Future Scope point 1. It... means we're already covering those operators. Why is there future scope needed? I otherwise agree with the current Open Issues directions. --Larry Garfield

Rowan Collins

8 years ago
On 27 June 2018 at 19:24, Levi Morrison <levim@php.net> wrote:
> This permits things such as NumPy to overload < to do an element-wise > comparison of the members; something like this: > > np.array([1, 3, 5, 7]) < np.array([2, 1, 6, 6]) > // evaluates to np.array([true, false, true, false) >
In my opinion, this is exactly the kind of messy operator overloading we should avoid, but if we DO want it, then its purpose is to over-ride the syntax, not the meaning, of the operator; so "overloaded <=>" would NOT be the same as "overloaded comparison". I think it's fairly crucial that this proposal is NOT just about overloading operators, it's about overloading *behaviour* which occurs throughout the language, and as such I think this statement from the RFC is incorrect:
> __compareTo is equivalent to <=> and __equals is equivalent to ==
If someone implements __compareTo() just to give some domain-specific meaning to the <=> operator, what will happen when someone passes those objects to sort()? If someone decides they want to return an object from __equals(), how will switch statements behave? And so on... Because of that, I would much rather these functions did enforce a return type. Note that __toString() generates an error for an incorrect return type when used, and __sleep() raises a Notice and serializes Null instead of the object. I think __compareTo() and __equals() could act more like a return type hint, and either throw a TypeError straight away, or attempt to coerce to the correct type and throw a TypeError on failure. Then, if we want the ability to override the <=> operator specifically, that can be added later, and users can return whatever type they want without breaking all the other places where __compareTo() is called. Regards,
-- Rowan Collins [IMSoP]

Rudolf Theunissen

8 years ago
> I think it's fairly crucial that this proposal is NOT just about
overloading operators, it's about overloading *behaviour* That is what this RFC is trying to achieve. Equivalent in behaviour, so we're providing a way for a class to define how it compares or equates to another value. We're not providing a way to override the meaning or function of the comparison operators, and it's up to the implementor to follow this advice. There's nothing stopping someone making `>` modify the object. But that's the nature of user-defined behaviour of operators: giving a developer more flexibility also increases the amount of weird stuff they can do. The question is simply whether the value of the flexibility is more than the cost of the potential for misuse. We're proposing the ability for a user to determine how a class should be compared to another value. The ability to change the semantics of the comparison operators is an unavoidable side effect.
> If someone implements __compareTo() just to give some domain-specific
meaning to the <=> operator That would be bad implementation on their part, and we should mention in the documentation update that this is not the intended application.
> I think __compareTo() and __equals() could act more like a return type
hint, and either throw a TypeError straight away, or attempt to coerce to the correct type and throw a TypeError on failure. Currently they do attempt to convert to boolean and integer, respectively, but that doesn't achieve much because you can still return nothing in either case and the coercion would be 0 and false.
-- The decision whether to accept this will come down to the trade-off between flexibility and potential for misuse. We're giving the developer more power and responsibility by adding to the capability of the language, but that can be said for any language-level change that has the potential for misuse. I would personally opt for more flexibility, with clear direction on the intended use, and trust that those who decide to leverage it know what they're doing. On Fri, 29 Jun 2018 at 13:35, Rowan Collins <rowan.collins@gmail.com> wrote:

Rowan Collins

8 years ago
On 30 June 2018 19:04:27 BST, Rudolf Theunissen <rudolf.theunissen@gmail.com> wrote:
>We're proposing the ability for a user to determine how a class should >be >compared to another value. The ability to change the semantics of the >comparison operators is an unavoidable side effect.
Absolutely, I agree with the intent of this RFC. I think what I was suggesting is that if people in future want to overload the operators specifically, we would want to provide an overload for <=> that was separate from __compareTo, so that you could overload that without breaking things like sorting.
>> I think __compareTo() and __equals() could act more like a return >type >hint, and either throw a TypeError straight away, or attempt to coerce >to >the correct type and throw a TypeError on failure. > >Currently they do attempt to convert to boolean and integer, >respectively, >but that doesn't achieve much because you can still return nothing in >either case and the coercion would be 0 and false.
Apologies if this is covered in the RFC, but does that apply wherever they are used? For instance, what will the following code do? class SpaceStation { public $shape; public function __construct($shape='[]') { $this->shape = $shape; } public function __compareTo($other) { return new self($this->shape . '>=<' . $other->shape); } } $a = new SpaceStation; $b = new SpaceStation; $c = $a <=> $b; // Error? 0? echo $c->shape; // or will this echo '[]>=<[]'? $d = $a < $b; // Same result? $list = [$a, $b, $c, $d]; sort($list); // Or will the error only be raised here?
>The decision whether to accept this will come down to the trade-off >between >flexibility and potential for misuse.
Absolutely, and for what it's worth (which isn't much) I'm +1 on this, if it's not documented as operator overloading (which I think is a separate feature) and can't be used to produce values outside the expected type (due to coercion or errors). Regards,
-- Rowan Collins [IMSoP]

Rudolf Theunissen

8 years ago
> > I think what I was suggesting is that if people in future want to overload > the operators specifically, we would want to provide an overload for <=> > that was separate from __compareTo, so that you could overload that without > breaking things like sorting.
I think it would be confusing to have both, or to have <=> not be aligned with __compareTo, because they are semantically equivalent. By overloading <=>, you have to also override comparison. Separating those is a recipe for confusion. Apologies if this is covered in the RFC, but does that apply wherever they
> are used? For instance, what will the following code do? > class SpaceStation { > public $shape; > public function __construct($shape='[]') { > $this->shape = $shape; > } > public function __compareTo($other) { > return new self($this->shape . '>=<' . $other->shape); > } > } > $a = new SpaceStation; > $b = new SpaceStation; > $c = $a <=> $b; // Error? 0? > echo $c->shape; // or will this echo '[]>=<[]'? > $d = $a < $b; // Same result? > $list = [$a, $b, $c, $d]; > sort($list); // Or will the error only be raised here?
When you use the `<=>` operator, the return value is normalised to either -1, 0 or 1 which is consistent with the current behaviour. So the object you're returning in `compareTo` will be converted to an integer(1) which will make `$c` be `1`. Attempting to call `echo $c->shape` then makes no sense. `$a < $b` will be false because according to your return of `1`, `$a` would be greater. Sorting would then consider the LHS to always be greater also. One thing that your example brings up is that `<=>` is not exactly equivalent to calling `__compareTo` directly, which would just return the raw value. This is exciting because it's a new issue that I'll add to the RFC for consideration. Ideally we would like the operator and the magic method to behave exactly the same, but that doesn't seem like a viable option because we wouldn't want to magically translate the return value of a function you're calling directly. The only option then is to simply advise that <=> will normalise the return value of `__compareTo`. I'm personally okay with that behaviour if it means the convention of the return value of <=> remains intact.

Rowan Collins

8 years ago
On 1 July 2018 19:45:03 BST, Rudolf Theunissen <rudolf.theunissen@gmail.com> wrote:
>> >> I think what I was suggesting is that if people in future want to >overload >> the operators specifically, we would want to provide an overload for ><=> >> that was separate from __compareTo, so that you could overload that >without >> breaking things like sorting. > > >I think it would be confusing to have both, or to have <=> not be >aligned >with __compareTo, because they are semantically equivalent. By >overloading ><=>, you have to also override comparison. Separating those is a recipe >for >confusion.
That's the point though: with operator overloading as defined in many languages, they're only semantically equivalent if the person overloading the operator wants them to be. The most well-known example is probably the C++ operator >> which for primitives is a bit shift, but is overloaded for input and output to streams. If, on the other hand, operator overloading was added but constrained by the language to certain return values, there would be very little to be gained by overloading each comparison separately - all the extra overloads would have to return boolean anyway.
>When you use the `<=>` operator, the return value is normalised to >either >-1, 0 or 1 which is consistent with the current behaviour. So the >object >you're returning in `compareTo` will be converted to an integer(1)
That makes perfect sense to me, thanks. Just to reiterate, it's *not* what fans of free-form operator overloading would want, but I think it's the right behaviour for this feature.
>One thing that your example brings up is that `<=>` is not exactly >equivalent to calling `__compareTo` directly, which would just return >the >raw value.
Yeah, that's a good point. Directly calling magic methods is always a bit peculiar, but I think a note in the manual is probably enough. Regards,
-- Rowan Collins [IMSoP]