digitalmars.D - Comparing apples and oranges
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Sep 29 2009
- Jeremie Pelletier <jeremiep gmail.com> Sep 29 2009
- Ary Borenszweig <ary esperanto.org.ar> Sep 29 2009
- "Denis Koroskin" <2korden gmail.com> Sep 29 2009
- bearophile <bearophileHUGS lycos.com> Sep 29 2009
- Jarrett Billingsley <jarrett.billingsley gmail.com> Sep 29 2009
- Stewart Gordon <smjg_1998 yahoo.com> Sep 29 2009
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Sep 29 2009
- Yigal Chripun <yigal100 gmail.com> Sep 29 2009
Consider:
class Apple {}
class Orange {}
void main() {
writeln(new Apple == new Orange);
}
This program always prints "false". By and large, it is odd that one
would attempt comparison between unrelated classes. I was thinking, is
this ever legitimate, or we should just disallow it statically whenever
possible?
The comparison would still remain possible by casting to a parent class:
writeln(cast(Object) new Apple == cast(Object) new Orange);
I could think of rare cases in which one would want two sibling types to
compare equal. Consider:
class Matrix { ... }
// No state added, operations optimized with BLAS
class BLASMatrix : Matrix {}
// No state added, operations optimized with LAPACK
class LAPACKMatrix : Matrix {}
Since neither derived class adds any state, both act in comparisons just
like the base class Matrix, so it's valid to compare a BLASMatrix with a
LAPACKMatrix.
How do you think we should go about this? Stay error-prone for the
benefit of a few cases, or disallow sibling class comparisons statically?
Andrei
Sep 29 2009
Andrei Alexandrescu wrote:Consider: class Apple {} class Orange {} void main() { writeln(new Apple == new Orange); } This program always prints "false". By and large, it is odd that one would attempt comparison between unrelated classes. I was thinking, is this ever legitimate, or we should just disallow it statically whenever possible? The comparison would still remain possible by casting to a parent class: writeln(cast(Object) new Apple == cast(Object) new Orange); I could think of rare cases in which one would want two sibling types to compare equal. Consider: class Matrix { ... } // No state added, operations optimized with BLAS class BLASMatrix : Matrix {} // No state added, operations optimized with LAPACK class LAPACKMatrix : Matrix {} Since neither derived class adds any state, both act in comparisons just like the base class Matrix, so it's valid to compare a BLASMatrix with a LAPACKMatrix. How do you think we should go about this? Stay error-prone for the benefit of a few cases, or disallow sibling class comparisons statically? Andrei
You can already explicitly do "(new Apple).opEquals(new Orange);" so why not first resolve == to opEquals and then try to match the parameters, walking through all known opEquals until a matching one is found.
Sep 29 2009
Andrei Alexandrescu wrote:Consider: class Apple {} class Orange {} void main() { writeln(new Apple == new Orange); } This program always prints "false". By and large, it is odd that one would attempt comparison between unrelated classes. I was thinking, is this ever legitimate, or we should just disallow it statically whenever possible?
Has this brought problems to anyone ever?
Sep 29 2009
Ary Borenszweig wrote:Andrei Alexandrescu wrote:Consider: class Apple {} class Orange {} void main() { writeln(new Apple == new Orange); } This program always prints "false". By and large, it is odd that one would attempt comparison between unrelated classes. I was thinking, is this ever legitimate, or we should just disallow it statically whenever possible?
Has this brought problems to anyone ever?
I'm not sure about this particular aspect, but in Java the related method equals() has been a perennial source of issues. Just google for java equals. Andrei
Sep 29 2009
On Tue, 29 Sep 2009 18:54:28 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Consider: class Apple {} class Orange {} void main() { writeln(new Apple == new Orange); } This program always prints "false". By and large, it is odd that one would attempt comparison between unrelated classes. I was thinking, is this ever legitimate, or we should just disallow it statically whenever possible? The comparison would still remain possible by casting to a parent class: writeln(cast(Object) new Apple == cast(Object) new Orange); I could think of rare cases in which one would want two sibling types to compare equal. Consider: class Matrix { ... } // No state added, operations optimized with BLAS class BLASMatrix : Matrix {} // No state added, operations optimized with LAPACK class LAPACKMatrix : Matrix {} Since neither derived class adds any state, both act in comparisons just like the base class Matrix, so it's valid to compare a BLASMatrix with a LAPACKMatrix. How do you think we should go about this? Stay error-prone for the benefit of a few cases, or disallow sibling class comparisons statically? Andrei
I believe Java and C# took bool Object.equals(Object other); way because they lacked generics intially and stored all the instances as Objects in containers (having equals method in Object allowed them proper ordering etc). D doesn't suffer from that problem and doesn't have to follow the same way those languages took. BTW, nowadays, they define IComparable<T> interface, which is a recommended way to implement comparison functions. That's why I'm all for removing opEquals from Object.
Sep 29 2009
Denis Koroskin:BTW, nowadays, they define IComparable<T> interface, which is a recommended way to implement comparison functions. That's why I'm all for removing opEquals from Object.
I think that asks for some extra optimizations that I think currently D front-end doesn't perform. Bye, bearophile
Sep 29 2009
On Tue, Sep 29, 2009 at 11:17 AM, Denis Koroskin <2korden gmail.com> wrote:I believe Java and C# took bool Object.equals(Object other); way because they lacked generics intially and stored all the instances as Objects in containers (having equals method in Object allowed them proper ordering etc). D doesn't suffer from that problem and doesn't have to follow the same way those languages took.
I agree, opEquals and opCmp in Object feel like out-of-date relics. It's particularly annoying how, if you want your classes to behave with arrays/AAs, you must override opEquals(Object), meaning you have to do silly downcasts at runtime.BTW, nowadays, they define IComparable<T> interface, which is a recommended way to implement comparison functions.
I think D, with its much better generic support, could basically use duck typing and achieve the same effects without the penalty of an interface.
Sep 29 2009
Jarrett Billingsley wrote:On Tue, Sep 29, 2009 at 11:17 AM, Denis Koroskin <2korden gmail.com> wrote:I believe Java and C# took bool Object.equals(Object other); way because they lacked generics intially and stored all the instances as Objects in containers (having equals method in Object allowed them proper ordering etc).
I believe Java still does internally, and generics are just a coding convenience. http://en.wikipedia.org/wiki/Generics_in_Java#Type_erasureD doesn't suffer from that problem and doesn't have to follow the same way those languages took.
I agree, opEquals and opCmp in Object feel like out-of-date relics. It's particularly annoying how, if you want your classes to behave with arrays/AAs, you must override opEquals(Object), meaning you have to do silly downcasts at runtime.
I've always been against opCmp being in Object. opEquals being in Object is harder to dismiss, as I can imagine that someone might find a use case for being able to store an arbitrary mix of objects in a container and in doing so be able to compare them. But I do wonder if Object.opEquals could work better. Maybe make it so that, if a class C contains a method opEquals(C), and opEquals(Object) has not been explicitly overridden by the programmer anywhere up the hierarchy, then opEquals(Object) will be automagically overridden to call opEquals(C). The only trouble is that I'm not sure how well this would work when interfaces are involved.BTW, nowadays, they define IComparable<T> interface, which is a recommended way to implement comparison functions.
Both Java's Comparable and, AFAICMO, .NET's IComparable, are for ordering comparisons. Equality comparison is built into Object in both cases. Stewart.
Sep 29 2009
Denis Koroskin wrote:On Tue, 29 Sep 2009 18:54:28 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Consider: class Apple {} class Orange {} void main() { writeln(new Apple == new Orange); } This program always prints "false". By and large, it is odd that one would attempt comparison between unrelated classes. I was thinking, is this ever legitimate, or we should just disallow it statically whenever possible? The comparison would still remain possible by casting to a parent class: writeln(cast(Object) new Apple == cast(Object) new Orange); I could think of rare cases in which one would want two sibling types to compare equal. Consider: class Matrix { ... } // No state added, operations optimized with BLAS class BLASMatrix : Matrix {} // No state added, operations optimized with LAPACK class LAPACKMatrix : Matrix {} Since neither derived class adds any state, both act in comparisons just like the base class Matrix, so it's valid to compare a BLASMatrix with a LAPACKMatrix. How do you think we should go about this? Stay error-prone for the benefit of a few cases, or disallow sibling class comparisons statically? Andrei
I believe Java and C# took bool Object.equals(Object other); way because they lacked generics intially and stored all the instances as Objects in containers (having equals method in Object allowed them proper ordering etc). D doesn't suffer from that problem and doesn't have to follow the same way those languages took. BTW, nowadays, they define IComparable<T> interface, which is a recommended way to implement comparison functions. That's why I'm all for removing opEquals from Object.
What would you replace it with? Note that IComparable<T> does not quite solve a lot of the problems, at least does not make things much easier for the programmer. Comparing objects is really a double dispatch problem. Andrei
Sep 29 2009
On 29/09/2009 18:13, Andrei Alexandrescu wrote:Denis Koroskin wrote:On Tue, 29 Sep 2009 18:54:28 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Consider: class Apple {} class Orange {} void main() { writeln(new Apple == new Orange); } This program always prints "false". By and large, it is odd that one would attempt comparison between unrelated classes. I was thinking, is this ever legitimate, or we should just disallow it statically whenever possible? The comparison would still remain possible by casting to a parent class: writeln(cast(Object) new Apple == cast(Object) new Orange); I could think of rare cases in which one would want two sibling types to compare equal. Consider: class Matrix { ... } // No state added, operations optimized with BLAS class BLASMatrix : Matrix {} // No state added, operations optimized with LAPACK class LAPACKMatrix : Matrix {} Since neither derived class adds any state, both act in comparisons just like the base class Matrix, so it's valid to compare a BLASMatrix with a LAPACKMatrix. How do you think we should go about this? Stay error-prone for the benefit of a few cases, or disallow sibling class comparisons statically? Andrei
I believe Java and C# took bool Object.equals(Object other); way because they lacked generics intially and stored all the instances as Objects in containers (having equals method in Object allowed them proper ordering etc). D doesn't suffer from that problem and doesn't have to follow the same way those languages took. BTW, nowadays, they define IComparable<T> interface, which is a recommended way to implement comparison functions. That's why I'm all for removing opEquals from Object.
What would you replace it with? Note that IComparable<T> does not quite solve a lot of the problems, at least does not make things much easier for the programmer. Comparing objects is really a double dispatch problem. Andrei
How about implementing multiple-dispatch than?
Sep 29 2009
Yigal Chripun wrote:On 29/09/2009 18:13, Andrei Alexandrescu wrote:Denis Koroskin wrote:On Tue, 29 Sep 2009 18:54:28 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Consider: class Apple {} class Orange {} void main() { writeln(new Apple == new Orange); } This program always prints "false". By and large, it is odd that one would attempt comparison between unrelated classes. I was thinking, is this ever legitimate, or we should just disallow it statically whenever possible? The comparison would still remain possible by casting to a parent class: writeln(cast(Object) new Apple == cast(Object) new Orange); I could think of rare cases in which one would want two sibling types to compare equal. Consider: class Matrix { ... } // No state added, operations optimized with BLAS class BLASMatrix : Matrix {} // No state added, operations optimized with LAPACK class LAPACKMatrix : Matrix {} Since neither derived class adds any state, both act in comparisons just like the base class Matrix, so it's valid to compare a BLASMatrix with a LAPACKMatrix. How do you think we should go about this? Stay error-prone for the benefit of a few cases, or disallow sibling class comparisons statically? Andrei
I believe Java and C# took bool Object.equals(Object other); way because they lacked generics intially and stored all the instances as Objects in containers (having equals method in Object allowed them proper ordering etc). D doesn't suffer from that problem and doesn't have to follow the same way those languages took. BTW, nowadays, they define IComparable<T> interface, which is a recommended way to implement comparison functions. That's why I'm all for removing opEquals from Object.
What would you replace it with? Note that IComparable<T> does not quite solve a lot of the problems, at least does not make things much easier for the programmer. Comparing objects is really a double dispatch problem. Andrei
How about implementing multiple-dispatch than?
Yah, how about it? :o) Andrei
Sep 29 2009









Jeremie Pelletier <jeremiep gmail.com> 