Using dmd 2.013 I'm now getting some messages along the lines of ...
warning: class Foo Object opCmp is hidden in Foo
What does this actually mean and how can I remove the warning (without
removing the -w switch)?
--
Derek Parnell
Melbourne, Australia
skype: derek.j.parnell
"Derek Parnell" <derek psych.ward> wrote in message
news:1pg84i0mr3ihw$.1ng68jjvixchm$.dlg 40tude.net...
Using dmd 2.013 I'm now getting some messages along the lines of ...
warning: class Foo Object opCmp is hidden in Foo
What does this actually mean and how can I remove the warning (without
removing the -w switch)?
It means that Object.opCmp has the signature "int(Object)" whereas your
class's opCmp has the signature "int(<something other than Object>)". In
other words, you're hiding the base class implementation of opCmp.
Try either putting 'override' on your implementation of opCmp, or doing
"alias super.opCmp opCmp" inside the class declaration. I'ven't got the D2
compiler on me to test :S
On Fri, 2 May 2008 22:47:33 -0400, Jarrett Billingsley wrote:
"Derek Parnell" <derek psych.ward> wrote in message
news:1pg84i0mr3ihw$.1ng68jjvixchm$.dlg 40tude.net...
Using dmd 2.013 I'm now getting some messages along the lines of ...
warning: class Foo Object opCmp is hidden in Foo
What does this actually mean and how can I remove the warning (without
removing the -w switch)?
It means that Object.opCmp has the signature "int(Object)" whereas your
class's opCmp has the signature "int(<something other than Object>)". In
other words, you're hiding the base class implementation of opCmp.
"hiding"?! Isn't one of the features of OO the ability to create
specialized methods that override the parent class' method of the same
signature?
Try either putting 'override' on your implementation of opCmp,
Tried that and got "function Foo.opCmp does not override any function"
or doing "alias super.opCmp opCmp" inside the class declaration.
Tried that and I got "basic type expected, not super"
Any other suggestions gladly accepted ;-)
--
Derek Parnell
Melbourne, Australia
skype: derek.j.parnell
May 02 2008
↑ ↓ ←→ Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Derek Parnell wrote:
On Fri, 2 May 2008 22:47:33 -0400, Jarrett Billingsley wrote:
"Derek Parnell" <derek psych.ward> wrote in message
news:1pg84i0mr3ihw$.1ng68jjvixchm$.dlg 40tude.net...
Using dmd 2.013 I'm now getting some messages along the lines of ...
warning: class Foo Object opCmp is hidden in Foo
What does this actually mean and how can I remove the warning (without
removing the -w switch)?
class's opCmp has the signature "int(<something other than Object>)". In
other words, you're hiding the base class implementation of opCmp.
"hiding"?! Isn't one of the features of OO the ability to create
specialized methods that override the parent class' method of the same
signature?
Yes, but to do that the signatures need to match. In this case, your
opCmp should take any Object (not just your specific subclass of it) and
return an int. Or at least, there should be an opCmp having such a
signature (i.e. it doesn't have to be the *only* opCmp overload).
Try either putting 'override' on your implementation of opCmp,
Tried that and got "function Foo.opCmp does not override any function"
This one only works to force you to get the signature right.
or doing "alias super.opCmp opCmp" inside the class declaration.
Tried that and I got "basic type expected, not super"
Try substituting 'super' by the class you directly inherit from. (That's
Object unless you mentioned one explicitly)
However, this will mean that when e.g. an object of your class is
compared to an Object or while the static type is Object the inherited
method will be called. Which would normally be a bad thing for opCmp.
Any other suggestions gladly accepted ;-)
Presumably your code currently looks something like:
---
class C {
int opCmp(C c) {
// implementation
}
}
---
If you want to get rid of the warning, try one of these:
---
class C {
/// Overrides Object.opCmp, throws if the argument is not a C.
override int opCmp(Object o) {
if (C c = cast(C) o)
return opCmp(c);
throw new Exception("Can't compare C to " ~ o.classinfo.name);
}
int opCmp(C c) {
// implementation
}
}
---
or
---
class C {
override int opCmp(Object o) {
if (C c = cast(C) o) {
// implementation
}
throw new Exception("Can't compare C to " ~ o.classinfo.name);
}
}
---
The second one is essentially the inlined version of the first, but will
be less efficient when the a and b in "a < b" are statically known to be
instances of C.
And both versions assume the argument isn't null; if you want to handle
null input (not sure why you would) you'll need some more checking.
On Sat, 03 May 2008 11:43:59 +0200, Frits van Bommel wrote:
"Derek Parnell" <derek psych.ward> wrote in message
news:1pg84i0mr3ihw$.1ng68jjvixchm$.dlg 40tude.net...
Using dmd 2.013 I'm now getting some messages along the lines of ...
warning: class Foo Object opCmp is hidden in Foo
What does this actually mean and how can I remove the warning (without
removing the -w switch)?
Presumably your code currently looks something like:
---
class C {
int opCmp(C c) {
// implementation
}
}
Yes it does.
---
If you want to get rid of the warning, try one of these:
---
class C {
/// Overrides Object.opCmp, throws if the argument is not a C.
override int opCmp(Object o) {
if (C c = cast(C) o)
return opCmp(c);
throw new Exception("Can't compare C to " ~ o.classinfo.name);
}
int opCmp(C c) {
// implementation
}
}
---
or
---
class C {
override int opCmp(Object o) {
if (C c = cast(C) o) {
// implementation
}
throw new Exception("Can't compare C to " ~ o.classinfo.name);
}
}
---
The second one is essentially the inlined version of the first, but will
be less efficient when the a and b in "a < b" are statically known to be
instances of C.
And both versions assume the argument isn't null; if you want to handle
null input (not sure why you would) you'll need some more checking.
OMG!!!
Firstly, this actually works!
Secondly, WTF!!! And how exactly is this making coding easier for people?
It would seem that every bloody time anyone codes a method that just
happens to be defined in Object, you need to go through this syntactially
hurdle to do something that seems so commonly required. For example, I also
coded 'toString' in my class, which meant that I have to now ALSO code this
waste of space ...
override string toString(){ return this.toString();}
This seems to be madness to me. What is it that I just not getting?
I want coding to be as easy as possible which means that I expect the
compiler to do the tedious work for me. Am I expecting too much? I mean, if
I code in MY class a method called "toString()" why does the compiler
bother to assume that I'm somehow referring to the method in Object?
--
Derek Parnell
Melbourne, Australia
skype: derek.j.parnell
May 03 2008
↑ ↓← → Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Derek Parnell wrote:
On Sat, 03 May 2008 11:43:59 +0200, Frits van Bommel wrote:
"Derek Parnell" <derek psych.ward> wrote in message
news:1pg84i0mr3ihw$.1ng68jjvixchm$.dlg 40tude.net...
Using dmd 2.013 I'm now getting some messages along the lines of ...
warning: class Foo Object opCmp is hidden in Foo
What does this actually mean and how can I remove the warning (without
removing the -w switch)?
Presumably your code currently looks something like:
---
class C {
int opCmp(C c) {
// implementation
}
}
Yes it does.
---
If you want to get rid of the warning, try one of these:
---
class C {
/// Overrides Object.opCmp, throws if the argument is not a C.
override int opCmp(Object o) {
if (C c = cast(C) o)
return opCmp(c);
throw new Exception("Can't compare C to " ~ o.classinfo.name);
}
int opCmp(C c) {
// implementation
}
}
---
or
---
class C {
override int opCmp(Object o) {
if (C c = cast(C) o) {
// implementation
}
throw new Exception("Can't compare C to " ~ o.classinfo.name);
}
}
---
The second one is essentially the inlined version of the first, but will
be less efficient when the a and b in "a < b" are statically known to be
instances of C.
And both versions assume the argument isn't null; if you want to handle
null input (not sure why you would) you'll need some more checking.
OMG!!!
Firstly, this actually works!
Secondly, WTF!!! And how exactly is this making coding easier for people?
It would seem that every bloody time anyone codes a method that just
happens to be defined in Object, you need to go through this syntactially
hurdle to do something that seems so commonly required. For example, I also
coded 'toString' in my class, which meant that I have to now ALSO code this
waste of space ...
override string toString(){ return this.toString();}
This seems to be madness to me. What is it that I just not getting?
This is only required when you want to implement a method with the same
name, but a different signature (return & parameter types). And IIRC you
can even change that slightly (accept superclasses of the original
parameter types and return a subclass of the original return type), but
I'm not sure about that one[1].
In other words: this is mostly an issue with opCmp and opEquals, not
most of the other Object methods (since those would normally keep the
same signature in subclasses).
For toString() it shouldn't be necessary. And in fact, your example
should produce an infinite recursion when called (you probably meant to
use 'super.toString()').
If you want to add an overload of toString (for example, one taking a
buffer so it doesn't have to return newly-allocated heap data) you can
'import' the superclass method using something like 'alias
Object.toString toString;' or 'alias super.toString toString;' (not sure
about the latter). This should be more efficient than calling
super.toString() since it avoids an extra call.
[1]: And if it does work, using interfaces instead of classes may fail
because they use different pointers (to the interface vtable in the
middle of the object, instead of the class vtable at the start).
I want coding to be as easy as possible which means that I expect the
compiler to do the tedious work for me. Am I expecting too much? I mean, if
I code in MY class a method called "toString()" why does the compiler
bother to assume that I'm somehow referring to the method in Object?
Because toString() is assumed to exist by several standard functions,
such as the write* family in Phobos and Stdout/Layout in Tango?
On Sat, 03 May 2008 11:43:59 +0200, Frits van Bommel wrote:
"Derek Parnell" <derek psych.ward> wrote in message
news:1pg84i0mr3ihw$.1ng68jjvixchm$.dlg 40tude.net...
Using dmd 2.013 I'm now getting some messages along the lines of ...
warning: class Foo Object opCmp is hidden in Foo
What does this actually mean and how can I remove the warning (without
removing the -w switch)?
Presumably your code currently looks something like:
---
class C {
int opCmp(C c) {
// implementation
}
}
Yes it does.
---
If you want to get rid of the warning, try one of these:
---
class C {
/// Overrides Object.opCmp, throws if the argument is not a C.
override int opCmp(Object o) {
if (C c = cast(C) o)
return opCmp(c);
throw new Exception("Can't compare C to " ~ o.classinfo.name);
}
int opCmp(C c) {
// implementation
}
}
---
or
---
class C {
override int opCmp(Object o) {
if (C c = cast(C) o) {
// implementation
}
throw new Exception("Can't compare C to " ~ o.classinfo.name);
}
}
---
The second one is essentially the inlined version of the first, but will
be less efficient when the a and b in "a < b" are statically known to be
instances of C.
And both versions assume the argument isn't null; if you want to handle
null input (not sure why you would) you'll need some more checking.
OMG!!!
Firstly, this actually works!
Secondly, WTF!!! And how exactly is this making coding easier for people?
It would seem that every bloody time anyone codes a method that just
happens to be defined in Object, you need to go through this syntactially
hurdle to do something that seems so commonly required. For example, I
also
coded 'toString' in my class, which meant that I have to now ALSO code
this
waste of space ...
override string toString(){ return this.toString();}
This seems to be madness to me. What is it that I just not getting?
I want coding to be as easy as possible which means that I expect the
compiler to do the tedious work for me. Am I expecting too much? I mean,
if
I code in MY class a method called "toString()" why does the compiler
bother to assume that I'm somehow referring to the method in Object?
I don't think you understand what the compiler is saying.
Look at a more pointed example:
class A
{
int foo(int i) {...}
}
class B : A
{
int foo(char[] c) {...}
}
Due to the simplified lookup rules of D, only B's foo or A's foo can be
called, depending on the instance type. I.e. D will only look in the most
derived scope of the static type that it finds the symbol 'foo', and won't
look any deeper at the base classes. So if you have:
B b = new B;
b.foo(1);
This will give you a compile-time error because you are trying to call A's
version of foo, but the compiler will only look at B's version, because that
is the scope it found foo's overload.
This is different than Java's lookup rules, which will look at base class
versions.
This is the SAME as C++ rules (which I was surprised to find out myself).
The question then becomes, what should happen in this case?
A a = new B;
a.foo(1);
This will compile, because the compiler knows that A has a foo(int) method.
However, there is some debate as to whether this should be allowed.
Walter's belief is that this should throw a hidden function exception. The
philosophy there is that if B is defining foo at all, it means to override
ALL versions of foo from the base class. Therefore, B doesn't want you
calling A's version of foo. In practice I think I have never needed this
functionality, nor can I see any reason for this, but this is Walter's
belief, and that's all that matters at this point :)
So now the latest D2 has a new warning (I thought it was an error, but no
matter) that you are compiling code that might throw an exception. This is
the reason for the warning.
If you want the Java behavior, you tell the compiler this by saying, "in
addition to these versions of foo, look at the base class' versions too" by
using alias:
class B
{
alias A.foo foo;
int foo(char[] c){...}
}
Now, all the above usage code of A and B compiles and does not throw an
exception.
My personal opinion is that this should be implicit. I can't see a reason
to have the C++ lookup rules over the Java rules, but that's my opinion, and
it differs from Walter's.
The reason you are having such trouble is because you are trying to override
the base class' version with a version that has a different signature. This
is not called overriding, but overloading. You are adding a NEW function to
the overload set. What you need to do is always override with the EXACT
same parameters as the base class. Look at the signatures for opCmp and
toString to see if they match your code. Using the override keyword helps
by ensuring the base class didn't change its signature and you didn't know
about it. If you use the override keyword and you are actually overloading,
not overriding, then the compiler gives an error.
The final thing is that you can override a base class' version of a
function, but return a co-variant type. That is, a type that implicitly
casts to the base class' return type. For example, if a function in your
base class returns an A, you can return a B and still override the same
function. That's because returning a B can be implicitly cast to returning
an A. This is handy so you don't have to upcast all the time when doing
things like chaining.
I hope this helps your understanding.
-Steve