All,
I've just written an RFC (with a patch against trunk) to implement a
Comparable interface similar to that in Java — in effect, allowing
object instances to be compared with semantics defined in userspace.
This is admittedly at the lower end of RFC-worthy proposals, but it's
a good system, and I'd like to see it used a little more. Plus, it's
good practice for the more interesting stuff to come. :)
The RFC is at http://wiki.php.net/rfc/comparable, and the patch at
http://www.adamharvey.name/patches/comparable.diff.txt. Any and all
feedback welcome, particularly since I'm still learning my way around
the innards of the Zend Engine, and it's entirely possible (indeed,
likely) that I've overlooked something obvious.
If there's no great resistance to the concept or implementation, I'm
happy enough to flip this into the voting stage sooner rather than
later so we can get it out of the way.
Thanks,
Adam
Hi Adam
2010/9/30 Adam Harvey aharvey@php.net:
All,
I've just written an RFC (with a patch against trunk) to implement a
Comparable interface similar to that in Java — in effect, allowing
object instances to be compared with semantics defined in userspace.
This is admittedly at the lower end of RFC-worthy proposals, but it's
a good system, and I'd like to see it used a little more. Plus, it's
good practice for the more interesting stuff to come. :)The RFC is at http://wiki.php.net/rfc/comparable, and the patch at
http://www.adamharvey.name/patches/comparable.diff.txt. Any and all
feedback welcome, particularly since I'm still learning my way around
the innards of the Zend Engine, and it's entirely possible (indeed,
likely) that I've overlooked something obvious.
I think its a great addition, but I think the interface should be
defined within ZE like the other base interfaces that interact
directly with the language syntax (like Iterator) and not in SPL.
The patch itself is flowlessly simple and I think it would be a great
addition for trunk, +1
--
regards,
Kalle Sommer Nielsen
kalle@php.net
I think its a great addition, but I think the interface should be
defined within ZE like the other base interfaces that interact
directly with the language syntax (like Iterator) and not in SPL.
s/should/has to/
The engine shall not depend on anthing in PHP. In theory you should be
able to do cd Zend && ./buildconf && ./configure && make to built a
PHP-less engine (needs TSRM somewhere though).
(Please mind my othe mail in this thread, too)
johannes
On Thu, 30 Sep 2010 15:26:17 +0100, Johannes Schlüter
johannes@schlueters.de wrote:
I think its a great addition, but I think the interface should be
defined within ZE like the other base interfaces that interact
directly with the language syntax (like Iterator) and not in SPL.s/should/has to/
The engine shall not depend on anthing in PHP. In theory you should be
able to do cd Zend && ./buildconf && ./configure && make to built a
PHP-less engine (needs TSRM somewhere though).
Right. Saying this is the way the Countable interface is implemented like
is said in the RFC is not really a valid argument, since the engine knows
nothing about that interface, only the "count" function (which is in the
standard extension) does.
--
Gustavo Lopes
2010/9/30 Johannes Schlüter johannes@schlueters.de:
I think its a great addition, but I think the interface should be
defined within ZE like the other base interfaces that interact
directly with the language syntax (like Iterator) and not in SPL.s/should/has to/
The engine shall not depend on anthing in PHP. In theory you should be
able to do cd Zend && ./buildconf && ./configure && make to built a
PHP-less engine (needs TSRM somewhere though).
Fair enough. I'll cook up a revised patch tomorrow that removes the
SPL dependency and moves the interface definition into Zend.
Adam
All,
I've just written an RFC (with a patch against trunk) to implement a
Comparable interface similar to that in Java — in effect, allowing
object instances to be compared with semantics defined in userspace.
This is admittedly at the lower end of RFC-worthy proposals, but it's
a good system, and I'd like to see it used a little more. Plus, it's
good practice for the more interesting stuff to come. :)
What is this "more interesting stuff to come"? - currently it is a bit
syntactic sugar, one might argue a feature which makes reading code
harder(*), and we are careful with adding such.
(*) Right now it is quite clear what happens if you read
$a == $b
there are a few edge cases (0 == "100000 mails ina thread") but overall
quite clear. With your patch "anything" might happen, which is hard to
detect as we don't enforce strong typing, which would give a hint.
johannes
All,
I've just written an RFC (with a patch against trunk) to implement a
Comparable interface similar to that in Java — in effect, allowing
object instances to be compared with semantics defined in userspace.
This is admittedly at the lower end of RFC-worthy proposals, but it's
a good system, and I'd like to see it used a little more. Plus, it's
good practice for the more interesting stuff to come. :)What is this "more interesting stuff to come"? - currently it is a bit
syntactic sugar, one might argue a feature which makes reading code
harder(*), and we are careful with adding such.(*) Right now it is quite clear what happens if you read
$a == $b
there are a few edge cases (0 == "100000 mails ina thread") but overall
quite clear. With your patch "anything" might happen, which is hard to
detect as we don't enforce strong typing, which would give a hint.
It sounds a little bit like operator over loading to me...
cheers,
Derick
--
http://derickrethans.nl | http://xdebug.org
Like Xdebug? Consider a donation: http://xdebug.org/donate.php
twitter: @derickr and @xdebug
(Omnibus reply, since Johannes's original e-mail hasn't yet dropped
into my ever-so-flaky mail setup. I have read it in full on
news.php.net, though.)
What is this "more interesting stuff to come"?
Nothing that's likely to be ready before the forthcoming release
cycle. I really did just want the RFC writing practice, since I
haven't done one within PHP's structure before. :)
(*) Right now it is quite clear what happens if you read
$a == $b
there are a few edge cases (0 == "100000 mails ina thread") but overall
quite clear. With your patch "anything" might happen, which is hard to
detect as we don't enforce strong typing, which would give a hint.
Sure, but I think by that argument interfaces like Countable,
Traversable and ArrayAccess would be out too. It is syntactic sugar,
but I think it's useful syntactic sugar.
One of the examples I toyed with tossing into the RFC was a date
class, but I figured the argument against that is the obvious one of
"people would use DateTime anyway". I think there are a range of
potential uses here.
2010/9/30 Derick Rethans derick@php.net:
It sounds a little bit like operator over loading to me...
I guess it is in a sense, since the comparison operators are by
definition operators. I don't really see this is as starting any sort
of slippery slope towards a full operator overloading implementation,
though -- it's limited in scope, and really seems like a small,
logical feature to make objects a little bit more useful to me.
Adam
What is this "more interesting stuff to come"?
Nothing that's likely to be ready before the forthcoming release
cycle. I really did just want the RFC writing practice, since I
haven't done one within PHP's structure before. :)
I take this answer as "There's no true benefit from this and I wrote
this patch just to learn" That's similar to the reasoning I had when
writing my operator overloading patch quite a few years ago, which I
never proposed and never would have proposed :-)
johannes
On Sun, 03 Oct 2010 15:16:05 +0100, Johannes Schlüter
johannes@schlueters.de wrote:
What is this "more interesting stuff to come"?
Nothing that's likely to be ready before the forthcoming release
cycle. I really did just want the RFC writing practice, since I
haven't done one within PHP's structure before. :)
I actually see no reason why we shouldn't expose the compare overload we
already have for internal classes to userspace classes.
However, the patch goes much further than this and, even if that direction
were desired, it takes, in my opinion, the wrong options in the details
I've mentioned.
--
Gustavo Lopes
On Sun, 03 Oct 2010 15:16:05 +0100, Johannes Schlüter
johannes@schlueters.de wrote:What is this "more interesting stuff to come"?
Nothing that's likely to be ready before the forthcoming release
cycle. I really did just want the RFC writing practice, since I
haven't done one within PHP's structure before. :)I actually see no reason why we shouldn't expose the compare overload we
already have for internal classes to userspace classes.
For internal classes it is needed, as they extend zend_object with
custom information we don't find in hash tables etc. so without the
internal handler we can't decide whether two objects are equal or not.
However, the patch goes much further than this and, even if that direction
were desired, it takes, in my opinion, the wrong options in the details
I've mentioned.
For userspace-defined classes the equal and other comparison operation
are clearly defined. (Well, maybe some of the conversions aren't always
that clear, but still follow rules)
When adding this feature the comparison operators change their
meaning ...
johannes
On Sun, 03 Oct 2010 15:37:41 +0100, Johannes Schlüter
johannes@schlueters.de wrote:
I actually see no reason why we shouldn't expose the compare overload we
already have for internal classes to userspace classes.For internal classes it is needed, as they extend zend_object with
custom information we don't find in hash tables etc. so without the
internal handler we can't decide whether two objects are equal or not.However, the patch goes much further than this and, even if that
direction were desired, it takes, in my opinion, the wrong options in
the
details I've mentioned.For userspace-defined classes the equal and other comparison operation
are clearly defined. (Well, maybe some of the conversions aren't always
that clear, but still follow rules)When adding this feature the comparison operators change their
meaning ...
You raise a fair point -- the motivation to override the comparison
operator for internal classes is indeed bigger because the state is not in
the usual places. However:
- The functionality already exists; comparison operators already have
their meaning "changed" (read: user-defined) for some objects. - I'd argue the current behavior (comparing classes and properties) is of
limited use for equality. It's common to lazy-load the properties of the
objects, which makes the current comparison behavior unreliable. - The current behavior for >, <, etc. is completely useless. It's
unpredictable and it doesn't even establish a total order:
$a = new stdclass;
$a->prop = null;
$b = new stdclass;
$b->prop2 = null;
var_dump($a > $b); //false
var_dump($a == $b); //false
var_dump($b > $a); //false
--
Gustavo Lopes
hi Gustavo,
You raise a fair point -- the motivation to override the comparison operator
for internal classes is indeed bigger because the state is not in the usual
places. However:
- The functionality already exists; comparison operators already have their
meaning "changed" (read: user-defined) for some objects.- I'd argue the current behavior (comparing classes and properties) is of
limited use for equality. It's common to lazy-load the properties of the
objects, which makes the current comparison behavior unreliable.- The current behavior for >, <, etc. is completely useless. It's
unpredictable and it doesn't even establish a total order:$a = new stdclass;
$a->prop = null;
$b = new stdclass;
$b->prop2 = null;var_dump($a > $b); //false
var_dump($a == $b); //false
var_dump($b > $a); //false
It may be why Stas' proposal could fit better, a comparable interface.
As there is then no confusion with undefined and useless behaviors
with normal comparison ops.
Cheers,
Pierre
@pierrejoye | http://blog.thepimp.net | http://www.libgd.org
Hi!
- The current behavior for>,<, etc. is completely useless. It's
unpredictable and it doesn't even establish a total order:$a = new stdclass;
$a->prop = null;
$b = new stdclass;
$b->prop2 = null;var_dump($a> $b); //false
var_dump($a == $b); //false
var_dump($b> $a); //false
That's because there's no total ordering of generic objects that can
make sense. Only very specific objects - such as ones representing
numeric qualities or having numeric properties - can be ordered, most of
objects are unordered. And comparing objects with scalars automagically
might bring a lot of surprises as nobody really expects $a == $b and $b
== $a to be different now.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
On Mon, 04 Oct 2010 00:18:36 +0100, Stas Malyshev smalyshev@sugarcrm.com
wrote:
- The current behavior for>,<, etc. is completely useless. It's
unpredictable and it doesn't even establish a total order:$a = new stdclass;
$a->prop = null;
$b = new stdclass;
$b->prop2 = null;var_dump($a> $b); //false
var_dump($a == $b); //false
var_dump($b> $a); //falseThat's because there's no total ordering of generic objects that can
make sense. Only very specific objects - such as ones representing
numeric qualities or having numeric properties - can be ordered, most of
objects are unordered. And comparing objects with scalars automagically
might bring a lot of surprises as nobody really expects $a == $b and $b
== $a to be different now.
I never defended comparison of objects against scalars (though this is
already possible, in a limited sense). Perhaps I ought to have changed the
subject.
I'm just saying that the current comparisons for user classes is either
very limited (==) or completely useless (<, >, >=, <=). Given that, we
could implement a limited mechanism for overloading those operators in
user-land. If limited to objects of the same class (or with one operand of
a subclass of the other), this could actually make the comparison
operators useful with little potential for damage. It would also not be
unprecedented since it's already allowed for internal classes.
--
Gustavo Lopes
$a = new stdclass;
$a->prop = null;
$b = new stdclass;
$b->prop2 = null;var_dump($a> $b); //false
var_dump($a == $b); //false
var_dump($b> $a); //falseThat's because there's no total ordering of generic objects that can
make sense. Only very specific objects - such as ones representing
numeric qualities or having numeric properties - can be ordered, most
of
objects are unordered. And comparing objects with scalars
automagically
might bring a lot of surprises as nobody really expects $a == $b and
$b
== $a to be different now.
If you make == not reflexive, I'd be pretty cranky... :-)
HOWEVER, here's an idea from left field...
If PHP is comparing OBJECTS and cannot discern an ordering, perhaps
returning NULL
instead of FALSE
would make sense.
I have NO IDEA if this is do-able, sensible, or reasonable...
It just struck me that when PHP doesn't "know" $a < $b should be
TRUE/FALSE, returning NULL
instead would be a "reasonable" course of
action, from this naive scripter's POV.
--
brain cancer update:
http://richardlynch.blogspot.com/search/label/brain%20tumor
Donate:
https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FS9NLTNEEKWBE
- The current behavior for >, <, etc. is completely useless. It's
unpredictable and it doesn't even establish a total order:$a = new stdclass;
$a->prop = null;
$b = new stdclass;
$b->prop2 = null;var_dump($a > $b); //false
var_dump($a == $b); //false
var_dump($b > $a); //false
Errrr.
Which one of these would you expect to be "true"?...
They're sure not equal, right?
And what would make $a or $b "greater" than the other? I mean, WHY
would you expect one of those to be "true", if you do expect one of
them to be "true"?
I sure can't find any logical a priori ordering, total, partial, or
otherwise.
Last time I checked, there was no "rule" that any set/graph or other
mathematical collection had to have a defined ordering, even partial.
But it's been ages since I got my Honors Math degree, so maybe they
changed the rule while I wasn't looking... :-)
--
brain cancer update:
http://richardlynch.blogspot.com/search/label/brain%20tumor
Donate:
https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FS9NLTNEEKWBE
- The current behavior for >, <, etc. is completely useless. It's
unpredictable and it doesn't even establish a total order:$a = new stdclass;
$a->prop = null;
$b = new stdclass;
$b->prop2 = null;var_dump($a > $b); //false
var_dump($a == $b); //false
var_dump($b > $a); //falseErrrr.
Which one of these would you expect to be "true"?...
They're sure not equal, right?
And what would make $a or $b "greater" than the other? I mean, WHY
would you expect one of those to be "true", if you do expect one of
them to be "true"?I sure can't find any logical a priori ordering, total, partial, or
otherwise.Last time I checked, there was no "rule" that any set/graph or other
mathematical collection had to have a defined ordering, even partial.But it's been ages since I got my Honors Math degree, so maybe they
changed the rule while I wasn't looking... :-)
Without addressing the appeal to authority argument, the problem is not
that there "must" be an ordering, partial or total.
The problem is that several algorithms expect a total order criterion to
exist; a notable example are sorting functions. While many will still
terminate when given a partial order, the results will be unpredictable.
So basically you have comparison function for objects, but you cannot, in
general, use it to sort even objects of the same class (seem my example).
Note that e.g. Java and .NET require a total order, see:
http://msdn.microsoft.com/en-us/library/system.icomparable.compareto.aspx
http://download.oracle.com/javase/6/docs/api/java/lang/Comparable.html#compareTo(T)
It would be somewhat useful to be able to sort objects by some (arbitrary)
total ordering criterion, e.g. to do a binary search afterwards, but
that's marginal to my argument, which is that the current object
comparison behavior ranges from limited to useless. Therefore, some
addition that would allow the user to give meaningful behavior to the
operators in some limited circumstances (e.g. comparisons inside classes
with inheritance relationships only) would be a good idea.
--
Gustavo Lopes
On Tue, 05 Oct 2010 04:31:14 +0100, Richard Lynch ceo@l-i-e.com
wrote:
- The current behavior for >, <, etc. is completely useless. It's
unpredictable and it doesn't even establish a total order:$a = new stdclass;
$a->prop = null;
$b = new stdclass;
$b->prop2 = null;var_dump($a > $b); //false
var_dump($a == $b); //false
var_dump($b > $a); //falseErrrr.
Which one of these would you expect to be "true"?...
They're sure not equal, right?
And what would make $a or $b "greater" than the other? I mean, WHY
would you expect one of those to be "true", if you do expect one of
them to be "true"?I sure can't find any logical a priori ordering, total, partial, or
otherwise.Last time I checked, there was no "rule" that any set/graph or other
mathematical collection had to have a defined ordering, even
partial.But it's been ages since I got my Honors Math degree, so maybe they
changed the rule while I wasn't looking... :-)Without addressing the appeal to authority argument, the problem is
not
that there "must" be an ordering, partial or total.The problem is that several algorithms expect a total order criterion
to
exist; a notable example are sorting functions. While many will still
terminate when given a partial order, the results will be
unpredictable.
So basically you have comparison function for objects, but you cannot,
in
general, use it to sort even objects of the same class (seem my
example).
But surely the generic case of an "Object" simply doesn't HAVE a
partial much less total ordering.
Forcing one to exist because a function exists that requires a stable
full ordering in order to call that function...
That's like forcing any string to be a valid JPEG because you might
feed it to imagecreatefromstring()
, in my eyes.
Note that e.g. Java and .NET require a total order, see:
PHP is not Java.
PHP is not .Net
I really don't see a valid reason why any given random collection of
OOP instances would a priori have to have a total ordering available
to them.
Certainly, I can see a zillion cases where domain-specific knowledge
of the objects and a comparison function/operator should be definable.
But I strongly object to forcing EVERY random collection of objects to
have a total ordering. It's creating order where order does not
exist.
It would be somewhat useful to be able to sort objects by some
(arbitrary)
total ordering criterion, e.g. to do a binary search afterwards, but
that's marginal to my argument, which is that the current object
comparison behavior ranges from limited to useless. Therefore, some
addition that would allow the user to give meaningful behavior to the
operators in some limited circumstances (e.g. comparisons inside
classes
with inheritance relationships only) would be a good idea.
I can certainly see why it would be useful to allow it in some cases.
But how tricky is it to write:
function foo_cmp($foo1, $foo2){ ... }
and hand that to usort?
--
brain cancer update:
http://richardlynch.blogspot.com/search/label/brain%20tumor
Donate:
https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FS9NLTNEEKWBE
- The current behavior for >, <, etc. is completely useless. It's
unpredictable and it doesn't even establish a total order:$a = new stdclass;
$a->prop = null;
$b = new stdclass;
$b->prop2 = null;var_dump($a > $b); //false
var_dump($a == $b); //false
var_dump($b > $a); //false[...]
Last time I checked, there was no "rule" that any set/graph or other
mathematical collection had to have a defined ordering, even
partial.[...]
[...] the problem is not that there "must" be an ordering, partial or
total.[...] You have comparison function for objects, but you cannot,
in general, use it to sort even objects of the same class (seem my
example).But surely the generic case of an "Object" simply doesn't HAVE a
partial much less total ordering.[...]
Note that e.g. Java and .NET require a total order, see:
PHP is not Java.
PHP is not .Net
I'm sorry, is this an argument?
You obviously don't know and didn't bother to check the details of the
Comparable interfaces in those languages and therefore did not understand
my point. They require a total ordering because that's precisely the only
way the comparison function can be useful for most applications. But
precisely because it doesn't make sense, as you say, to have total
ordering for the full set of objects, not all objects implement such
interface.
This contrasts with PHP, which allows without error comparison of all
objects, but you can't do anything useful with it.
Certainly, I can see a zillion cases where domain-specific knowledge
of the objects and a comparison function/operator should be definable.But I strongly object to forcing EVERY random collection of objects to
have a total ordering. It's creating order where order does not
exist.
I don't care either way, but, if implemented an arbitrary total order
(e.g. using the object id), it wouldn't be worse than the status quo.
It would be somewhat useful to be able to sort objects by some
(arbitrary)
total ordering criterion, e.g. to do a binary search afterwards, but
that's marginal to my argument, which is that the current object
comparison behavior ranges from limited to useless. Therefore, some
addition that would allow the user to give meaningful behavior to the
operators in some limited circumstances (e.g. comparisons inside
classes with inheritance relationships only) would be a good idea.I can certainly see why it would be useful to allow it in some cases.
But how tricky is it to write:
function foo_cmp($foo1, $foo2){ ... }
and hand that to usort?
It's not tricky, but it's besides the point. We don't need many other
operators either, we could just write a custom function and use it instead.
The point is -- I'm going to reiterate this one last time -- for objects,
you can't do anything useful with the current zend_compare_function,
therefore a limited mechanism for overloading it would be useful.
Notice you didn't provide any argument otherwise and instead admitted (for
whatever reason) I was defending a total order should be established for
all the objects.
--
Gustavo Lopes
I've just written an RFC (with a patch against trunk) to implement a
Comparable interface similar to that in Java — in effect, allowing
object instances to be compared with semantics defined in userspace.
This is admittedly at the lower end of RFC-worthy proposals, but it's
a good system, and I'd like to see it used a little more. Plus, it's
good practice for the more interesting stuff to come. :)The RFC is at http://wiki.php.net/rfc/comparable, and the patch at
http://www.adamharvey.name/patches/comparable.diff.txt. Any and all
feedback welcome, particularly since I'm still learning my way around
the innards of the Zend Engine, and it's entirely possible (indeed,
likely) that I've overlooked something obvious.If there's no great resistance to the concept or implementation, I'm
happy enough to flip this into the voting stage sooner rather than
later so we can get it out of the way.
I think this would be a good idea if limited to provide a userspace
alternative to compare_objects, like Countable provides a userspace
alternative to count_elements.
That is, you would only modify zend_std_compare_objects (not
compare_function!) and add there the additional logic where you'd check if
the objects had the same class (or perhaps one was of a subclass of the
other, in which case you'd use the compare method of the subclass) and
call the compare method.
Allowing comparison of objects with non-objects can become very confusing:
- What if the objects are not of the same class? What if one is of a
subclass of the other? Is equality not symmetric? - How do you interact with 'get' and 'cast_object'/'__tostring'?
It's true that there's already overloading of '==' for internal classes,
but it's very predictable: both operands must have the same
'compare_objects', otherwise it's not used.
For the record, the current rules are relatively simple:
- If both are objects and have the same 'compare_objects' handler, use it.
- If the first operand is an object and has a 'get' (tried first) or
'cast_object' handler call it, and repeat with the new value. - Try the same for the second operand.
--
Gustavo Lopes
That is, you would only modify zend_std_compare_objects (not
compare_function!) and add there the additional logic where you'd check if
the objects had the same class (or perhaps one was of a subclass of the
other, in which case you'd use the compare method of the subclass) and call
the compare method.Allowing comparison of objects with non-objects can become very confusing:
- What if the objects are not of the same class? What if one is of a
subclass of the other? Is equality not symmetric?- How do you interact with 'get' and 'cast_object'/'__tostring'?
The initial version of the patch actually did just that: it simply
modified zend_std_compare_objects. That's pretty much the cleanest way
you could do it. :)
I dropped it and went with the more complicated approach involving
changing compare_function because I actually think allowing comparison
with non-objects is a valuable feature. Objects may be more strongly
typed in PHP than scalars, but there's still a certain amount of
juggling that can take place via __toString(), so I think it would be
out of place to require an object on both sides. Additionally, there
are already semantics built into compare_function to handle
object/non-object comparisons, although they're of very limited use in
practice.
The specific use case I had in mind was allowing comparisons of
objects representing monetary amounts against numeric values (since
that was a particular itch I had a couple of years ago), but I'm sure
there would be others.
In terms of the specific question as to whether equality is symmetric:
certainly it should be, but we would have no way of enforcing it,
obviously. Java doesn't either, though: there's simply a note in the
documentation saying that implementations should be symmetric.
Adam
The initial version of the patch actually did just that: it simply
modified zend_std_compare_objects. That's pretty much the cleanest way
you could do it. :)(...) Additionally, there
are already semantics built into compare_function to handle
object/non-object comparisons, although they're of very limited use in
practice.The specific use case I had in mind was allowing comparisons of
objects representing monetary amounts against numeric values (since
that was a particular itch I had a couple of years ago), but I'm sure
there would be others.
It's true that the engine already allows comparison of objects with
scalars, but that can only happen after a cast. At least you now have the
guarantee that if you compare a scalar x of type u with an object y and
they're equal, then x === (u) y is also true*.
With your patch, you could make $obj == "jjj" be true and (string) $obj
yield a completely different thing. Obviously you wouldn't do this on
purpose, my point is that this could lead to a hard to debug problem.
This is what makes me very reluctant to support this more general approach
of allowing scalar-object comparisons.
- (maybe there's some edge case where this wouldn't happen because the
engine is inconsistent with its preferences towards get, cast_object and
__toString, but my point stands)
In terms of the specific question as to whether equality is symmetric:
certainly it should be, but we would have no way of enforcing it,
obviously. Java doesn't either, though: there's simply a note in the
documentation saying that implementations should be symmetric.
Obviously it must be the programmer's responsibility to write a compare()
function that is symmetric (and in general, establish a total order).
My point about about symmetry was another: you know have potentially
different code running in these two cases:
$a == $b
$b == $a
The current implementation is "symmetric" in the sense the compare_objects
handler is called only if both objects have the same handler (only the
arguments are exchanged).
--
Gustavo Lopes
Hi!
The RFC is at http://wiki.php.net/rfc/comparable, and the patch at
http://www.adamharvey.name/patches/comparable.diff.txt. Any and all
feedback welcome, particularly since I'm still learning my way around
the innards of the Zend Engine, and it's entirely possible (indeed,
likely) that I've overlooked something obvious.
It is not clear from the RFC, if the engine encounters $a <= $b, what
actually happens?
E.g.:
- Is only $a checked for Comparable or also $b?
- How it is ensured that if $a < $b then $b > $a?
- Would sorting work with it?
- If both $a and $b are objects with different compare functions, how
it is determined whose function is used? Note that operators like == are
assumed to be commutative, and less/more operators are assumed to be
commutative in pairs, like above.
As a side note, if we have traits we might instead think of having
Comparable trait or interface or both, which would declare having
compareTo() standard feature (as Java does) without messing with the
engine and overloading operators. Surely, it would be more verbose, but
that might be a good thing.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
For what it's worth, I'm planning to update the RFC later today with
an updated SPL-less patch and the start of a Q&A section similar to
what we've had in the other RFCs. I'll send an e-mail when it's ready.
It is not clear from the RFC, if the engine encounters $a <= $b, what
actually happens?
E.g.:
- Is only $a checked for Comparable or also $b?
Both $a and $b are checked.
- How it is ensured that if $a < $b then $b > $a?
That's up to the userspace developer to get right when they're
implementing their compareTo method. I expect the manual would have a
dire warning about the possible consequences of not making them
equivalent.
- Would sorting work with it?
Yes.
- If both $a and $b are objects with different compare functions, how it is
determined whose function is used? Note that operators like == are assumed
to be commutative, and less/more operators are assumed to be commutative in
pairs, like above.
The left operand wins, so $a.
As a side note, if we have traits we might instead think of having
Comparable trait or interface or both, which would declare having
compareTo() standard feature (as Java does) without messing with the engine
and overloading operators. Surely, it would be more verbose, but that might
be a good thing.
I don't think that gains us an awful lot (it's no different to simply
having an interface or trait within a codebase requiring such a
function, which has been common practice in some of the systems I work
on anyway), but it'd be easy enough to add, obviously.
Adam
I've just written an RFC (with a patch against trunk) to implement a
Comparable interface similar to that in Java — in effect, allowing
object instances to be compared with semantics defined in userspace.
This is admittedly at the lower end of RFC-worthy proposals, but it's
a good system, and I'd like to see it used a little more. Plus, it's
good practice for the more interesting stuff to come. :)
I've updated the RFC with a fresh patch that doesn't involve SPL at
all and attempted to incorporate some of the questions and answers so
far into the RFC. I've also added a section for concerns with the RFC;
I've attempted to distil the concerns I've seen so far, but please
feel free to edit that list if specific concerns are misrepresented or
unrepresented.
Links:
RFC: http://wiki.php.net/rfc/comparable
Patch v2: http://www.adamharvey.name/patches/comparable-v2.diff.txt
Thanks,
Adam
I've just written an RFC (with a patch against trunk) to implement a
Comparable interface similar to that in Java — in effect, allowing
object instances to be compared with semantics defined in userspace.
This is admittedly at the lower end of RFC-worthy proposals, but it's
a good system, and I'd like to see it used a little more. Plus, it's
good practice for the more interesting stuff to come. :)I've updated the RFC with a fresh patch that doesn't involve SPL at
all and attempted to incorporate some of the questions and answers so
far into the RFC. I've also added a section for concerns with the RFC;
I've attempted to distil the concerns I've seen so far, but please
feel free to edit that list if specific concerns are misrepresented or
unrepresented.Links:
RFC: http://wiki.php.net/rfc/comparable
Patch v2: http://www.adamharvey.name/patches/comparable-v2.diff.txt
Here's a new concern: I find a bad idea to call compareTo before
'compare_objects'. This means that if in your internal class you define
your own comparison logic with 'compare_objects', you cannot make sure the
userland subclasses won't completely replace your logic by implementing
Comparable. So to prevent this you'd have to implement 'Comparable'
yourself...
The low level feature should have priority (look at e.g. Countable vs
count_objects); you could always in your 'compare_objects' check for the
interface and call it if you want to allow userspace subclasses to replace
the comparison logic.
The RFC says:
How do you interact with 'get' and 'cast_object'/'__tostring'?
The tests for whether the operands implement Comparable occur before
any potential calls to get and cast_object.
So basically this means that 'get' and 'cast_object' will never be called
of an object $a will never be called if it's being compared to a
Comparable object $b, right?
This is not a very good idea because it puts the responsibility to deal
correctly with proxy objects and scalar castable objects on the part of
the implementor of the compareTo method.
Tis means people implementing compareTo natively will almost never get it
right. Let's say they want to make their object comparable with integers.
You pass a proxy object that yields integers. Now the native implementor
sees an object and must remember to check for the existence of 'get' and
'cast_object' and call them if necessary. Right.
For userland implementations, the situation is not much better; the
implementor for compare would (most likely) have to do an explicit cast to
the type he wants to compare with and, of course, using stuff like
'gettype' would probably result in wrong behavior.
TL;DR: 'get' and 'cast_object' should be checked for and, if necessary,
called first.
If both $a and $b are objects with different compare functions,
how it is determined whose function is used? Note that operators
like == are assumed to be commutative, and less/more operators
are assumed to be commutative in pairs, like above.
The left operand wins, so $a.
At least in Java, it's clear this is happening because you call
a.compareTo(b). This is a dangerous feature... In my opinion, if they have
different compareTo implementations, they shouldn't be compared.
--
Gustavo Lopes
hi Adam,
Thanks for writing and updating a RFC, always the best way to propose
new features :)
I've just written an RFC (with a patch against trunk) to implement a
Comparable interface similar to that in Java — in effect, allowing
object instances to be compared with semantics defined in userspace.
This is admittedly at the lower end of RFC-worthy proposals, but it's
a good system, and I'd like to see it used a little more. Plus, it's
good practice for the more interesting stuff to come. :)I've updated the RFC with a fresh patch that doesn't involve SPL at
all and attempted to incorporate some of the questions and answers so
far into the RFC. I've also added a section for concerns with the RFC;
I've attempted to distil the concerns I've seen so far, but please
feel free to edit that list if specific concerns are misrepresented or
unrepresented.
Maybe to get a context about how other languages work (or do not work)
with these similar features, it could be interesting to look at the
python (2.5) documentation:
http://docs.python.org/release/2.5.2/ref/customization.html
As I would be in favor of having a compareTo interface for similar
objects, I worry a bit about comparing apple and pear. Yes, an apple
can be greater than a pear in real world but the wtf is somehow huge
in a php context. That's why I share Stas or Gustavo thoughts about
comparing instances of different classes (or with inheritance from
internal classes without a comparable implementation).
To be more precised, by "wtf", I mean that $a == $b may not mean that
$b == $a (as in python for example). That's something we should
consider carefully.
Cheers,
Pierre
@pierrejoye | http://blog.thepimp.net | http://www.libgd.org
If there's no great resistance to the concept or implementation, I'm
happy enough to flip this into the voting stage sooner rather than
later so we can get it out of the way.
If I'm understanding this correctly, you're going to make it WAY too
easy for scripters to screw up == and === and create bugs that are
impossible to track down...
Please, no.
-1
--
brain cancer update:
http://richardlynch.blogspot.com/search/label/brain%20tumor
Donate:
https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FS9NLTNEEKWBE