On 27/09/2009 19:01, Andrei Alexandrescu wrote:
grauzone wrote:
Andrei Alexandrescu wrote:
Here's an article about the perils of equals in Java (opEquals in D):
http://www.ddj.com/article/printableArticle.jhtml;jsessionid=GFKUCQH5S4IHNQE1GHOSKHWATMY32JVN?articleID=184405053&dept_url=/java/
It turns out this is a great example for NVI. In D, we could and should
do the following:
class Object {
// Implement this
private bool opEqualsImpl(Object rhs) {
return false;
}
// Use this
final bool opEquals(Object rhs) {
if (this is rhs) return true;
if (this is null || rhs is null) return false;
return opEqualsImpl(rhs) && rhs.opEqualsImpl(this);
}
}
I took advantage of the fact that in a final function this may be null
without an access violation. The implementation above ensures symmetry
of equality and has each class implement a simpler primitive.
What do you think?
Eh, now after all this discussion, we're going to allow even "this" to
be null? That seems like a backstep...
Good point.
Implementing opEquals as a global/static function, that calls the
actual Object.opEquals virtual method would be so much more straight
forward.
It's also less safe because people could call the incomplete primitive
by hand. With NVI in place nobody outside object.d could ever call
opEqualsImpl.
PS: I agree about the NVI thing. If you'd go to extend the language
for "NVI", couldn't we just introduce a second type of virtual
function that works this way:
1. the super class' implementation is _always_ called first
2. the super class function can decide to "call down" to the sub
class' implementation of the same method
=> no extra do<something> method needed, and the code is (possibly)
clearer.
Do you know of a precedent for this? One thing that NVI has going for it
is that it's quite established - it seems to be solidly planted in
programmers' lore. I was surprised to find 2.8M Google matches for the
exact string "Non-Virtual Interface".
Andrei
This is a smalltalk idea -
method:
^ self method
by sending a message to self without implementing it you make the method
abstract.
of course you can add pre/post code.
I also seen this with the keyword inner:
class Foo {
void bar() {
... setup
inner();
...tear down
}
}