Thread overview
warning ... is hidden in ...
May 03, 2008
Derek Parnell
May 03, 2008
Derek Parnell
May 03, 2008
Frits van Bommel
May 03, 2008
Derek Parnell
May 03, 2008
Frits van Bommel
May 03, 2008
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
May 03, 2008
"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


May 03, 2008
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 03, 2008
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)?
>>>
>> 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?  

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.
May 03, 2008
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
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?
May 05, 2008
"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?
>
> 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