469,604 Members | 2,377 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,604 developers. It's quick & easy.

Confused by overloading (or can I claim it's a compiler bug...?)

AJ
Why does the following behave as it does...?

public class Base
{
public void Add( byte b )
{
}
}

public class TestClass : Base
{
public void Add( int s )
{
byte x = 0;
Add( x );
}
}

then call with
new TestClass().Add( 10 );

-The Add(int) override gets called (good). Which in turn class the
___Add(int)___ override.

Why doesn't this second call hit the base class's Add( byte ) ??

[It works as I'd expected if the Add(byte) method is defined in
TestClass rather than Base, or you call base.Add(x) ]
Mar 26 '07 #1
15 1186
On Mar 26, 11:05 am, AJ <n...@nowhere.comwrote:
Why does the following behave as it does...?

public class Base
{
public void Add( byte b )
{
}
}

public class TestClass : Base
{
public void Add( int s )
{
byte x = 0;
Add( x );
}
}

then call with
new TestClass().Add( 10 );

-The Add(int) override gets called (good). Which in turn class the
___Add(int)___ override.

Why doesn't this second call hit the base class's Add( byte ) ??

[It works as I'd expected if the Add(byte) method is defined in
TestClass rather than Base, or you call base.Add(x) ]
Look at your compiler errors; you should be getting a warning that
TestClass is hiding a member of the base class. You need to add the
virtual keyword to the method definition in the base class, then add
the overrides keyword to the method definition in the subclass. If
you need to call the base, you need to do so yourself.

Mar 26 '07 #2
That's not correct. There is no hiding here.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Andy" <an***@med-associates.comwrote in message
news:11*********************@y80g2000hsf.googlegro ups.com...
On Mar 26, 11:05 am, AJ <n...@nowhere.comwrote:
>Why does the following behave as it does...?

public class Base
{
public void Add( byte b )
{
}
}

public class TestClass : Base
{
public void Add( int s )
{
byte x = 0;
Add( x );
}
}

then call with
new TestClass().Add( 10 );

-The Add(int) override gets called (good). Which in turn class the
___Add(int)___ override.

Why doesn't this second call hit the base class's Add( byte ) ??

[It works as I'd expected if the Add(byte) method is defined in
TestClass rather than Base, or you call base.Add(x) ]

Look at your compiler errors; you should be getting a warning that
TestClass is hiding a member of the base class. You need to add the
virtual keyword to the method definition in the base class, then add
the overrides keyword to the method definition in the subclass. If
you need to call the base, you need to do so yourself.

Mar 26 '07 #3
AJ
In article <11*********************@y80g2000hsf.googlegroups. com>,
an***@med-associates.com says...
On Mar 26, 11:05 am, AJ <n...@nowhere.comwrote:
Why does the following behave as it does...?

public class Base
{
public void Add( byte b )
{
}
}

public class TestClass : Base
{
public void Add( int s )
{
byte x = 0;
Add( x );
}
}

then call with
new TestClass().Add( 10 );

-The Add(int) override gets called (good). Which in turn class the
___Add(int)___ override.

Why doesn't this second call hit the base class's Add( byte ) ??

[It works as I'd expected if the Add(byte) method is defined in
TestClass rather than Base, or you call base.Add(x) ]

Look at your compiler errors; you should be getting a warning that
TestClass is hiding a member of the base class. You need to add the
virtual keyword to the method definition in the base class, then add
the overrides keyword to the method definition in the subclass. If
you need to call the base, you need to do so yourself.

I'm overloading, not overriding..

Mar 26 '07 #4
On Mar 26, 4:05 pm, AJ <n...@nowhere.comwrote:

<snip>
-The Add(int) override gets called (good). Which in turn class the
___Add(int)___ override.

Why doesn't this second call hit the base class's Add( byte ) ??
<snip>

Because the spec is very, very weird when it comes to overloading.
>From memory, when it tries to work out which overload to take, if
there are *any* valid signatures (i.e. ones which can match with
implicit conversion) in a more derived class than a less derived
class, all signatures in the less derived class are effectively
removed.

What's even weirder is that this includes signatures which are
overridden in the derived class:
using System;

class Base
{
public virtual void Foo(string x)
{
Console.WriteLine ("Base.Foo(string)");
}
}

class Derived : Base
{
public override void Foo(string x)
{
Console.WriteLine ("Derived.Foo(string)");
}

public void Foo(object x)
{
Console.WriteLine ("Derived.Foo(object)");
}
}

class Test
{
static void Main()
{
new Derived().Foo("Hello");
}
}

The output, contrary to intuitive expectations, is
"Derived.Foo(object)".

It's bonkers if you ask me, but that's what the spec says...

Jon

Mar 26 '07 #5
AJ
In article <11**********************@p77g2000hsh.googlegroups .com>,
sk***@pobox.com says...
On Mar 26, 4:05 pm, AJ <n...@nowhere.comwrote:

<snip>
-The Add(int) override gets called (good). Which in turn class the
___Add(int)___ override.

Why doesn't this second call hit the base class's Add( byte ) ??

<snip>

Because the spec is very, very weird when it comes to overloading.
From memory, when it tries to work out which overload to take, if
there are *any* valid signatures (i.e. ones which can match with
implicit conversion) in a more derived class than a less derived
class, all signatures in the less derived class are effectively
removed.

What's even weirder is that this includes signatures which are
overridden in the derived class:
That's nasty..... So, if my original example started as a single class,
then I refactor to create the base class (without changing anything
else), I suddenly get different behaviour (because the Add(byte) is no
longer being called.)

Ugh. Ugh. Ugh.

Mar 26 '07 #6
On Mar 26, 4:55 pm, AJ <n...@nowhere.comwrote:
What's even weirder is that this includes signatures which are
overridden in the derived class:

That's nasty..... So, if my original example started as a single class,
then I refactor to create the base class (without changing anything
else), I suddenly get different behaviour (because the Add(byte) is no
longer being called.)

Ugh. Ugh. Ugh.
Absolutely. I believe this to be unintentional. When I contacted a
couple of members of the ECMA committee, they were somewhat horrified
too :)

Jon

Mar 26 '07 #7
AJ
In article <11**********************@n76g2000hsh.googlegroups .com>,
sk***@pobox.com says...
On Mar 26, 4:55 pm, AJ <n...@nowhere.comwrote:
What's even weirder is that this includes signatures which are
overridden in the derived class:
That's nasty..... So, if my original example started as a single class,
then I refactor to create the base class (without changing anything
else), I suddenly get different behaviour (because the Add(byte) is no
longer being called.)

Ugh. Ugh. Ugh.

Absolutely. I believe this to be unintentional. When I contacted a
couple of members of the ECMA committee, they were somewhat horrified
too :)
Do you mean an unintentional sideeffect of the rules, or an unitentional
'feature' in the compiler?

I've just briefly downloaded and looked at "ECMA-334 C# Language
specification 4th Edition/ June 2006"

I can see rules about deciding which overloaded function to use (sect.
14.4.2) , but can't see any mention that inheritance comes into the
decision..

Mar 26 '07 #8
VJ
This really explains a problem we had in the last 2 days, and I was finally
going to post. This helps..! Thanks Jon.. AJ...

VJ
"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:11**********************@p77g2000hsh.googlegr oups.com...
On Mar 26, 4:05 pm, AJ <n...@nowhere.comwrote:

<snip>
>-The Add(int) override gets called (good). Which in turn class the
___Add(int)___ override.

Why doesn't this second call hit the base class's Add( byte ) ??

<snip>

Because the spec is very, very weird when it comes to overloading.
>>From memory, when it tries to work out which overload to take, if
there are *any* valid signatures (i.e. ones which can match with
implicit conversion) in a more derived class than a less derived
class, all signatures in the less derived class are effectively
removed.

What's even weirder is that this includes signatures which are
overridden in the derived class:
using System;

class Base
{
public virtual void Foo(string x)
{
Console.WriteLine ("Base.Foo(string)");
}
}

class Derived : Base
{
public override void Foo(string x)
{
Console.WriteLine ("Derived.Foo(string)");
}

public void Foo(object x)
{
Console.WriteLine ("Derived.Foo(object)");
}
}

class Test
{
static void Main()
{
new Derived().Foo("Hello");
}
}

The output, contrary to intuitive expectations, is
"Derived.Foo(object)".

It's bonkers if you ask me, but that's what the spec says...

Jon

Mar 26 '07 #9
AJ <no***@nowhere.comwrote:
Absolutely. I believe this to be unintentional. When I contacted a
couple of members of the ECMA committee, they were somewhat horrified
too :)

Do you mean an unintentional sideeffect of the rules, or an unitentional
'feature' in the compiler?
Unintentional side-effect of the rules. The compiler obeys the spec
here.
I've just briefly downloaded and looked at "ECMA-334 C# Language
specification 4th Edition/ June 2006"

I can see rules about deciding which overloaded function to use (sect.
14.4.2) , but can't see any mention that inheritance comes into the
decision..
It's in 14.5.5.1:

<quote>
The set of candidate methods is reduced to contain only methods from
the most derived types: For each method C.F in the set, where C is the
type in which the method F is declared, all methods declared in a
base type of C are removed from the set.
</quote>

(An overriding method doesn't count as a declaration - the declaration
is in the base class.)

It's not the easiest spec in the world to navigate, unfortunately.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 26 '07 #10
Jon Skeet [C# MVP] wrote:
Because the spec is very, very weird when it comes to overloading.
It's actually with good reason: it makes it safe to add new overloads to
base classes in the framework without worrying that existing programs
are going to break when recompiled, due to finding the new overload when
the new framework is released.
It's bonkers if you ask me, but that's what the spec says...
AndersH actually appears to be very proud of this feature of C#, I
recall watching a video where he pointed out that he wasn't aware of any
other language that did overloading this way.

-- Barry

--
http://barrkel.blogspot.com/
Mar 27 '07 #11
Jon Skeet [C# MVP] wrote:
The output, contrary to intuitive expectations, is
"Derived.Foo(object)".

It's bonkers if you ask me, but that's what the spec says...
Whups - I do agree with you about the overridden version though, it
shouldn't remove overridden overloads, as that's evidence that the
descendant is aware of the ancestor's method.

-- Barry

--
http://barrkel.blogspot.com/
Mar 27 '07 #12
Barry Kelly <ba***********@gmail.comwrote:
Jon Skeet [C# MVP] wrote:
Because the spec is very, very weird when it comes to overloading.

It's actually with good reason: it makes it safe to add new overloads to
base classes in the framework without worrying that existing programs
are going to break when recompiled, due to finding the new overload when
the new framework is released.
That's a reasonable point - but I still find it counterintuitive, and
it seems that others do too.
It's bonkers if you ask me, but that's what the spec says...

AndersH actually appears to be very proud of this feature of C#, I
recall watching a video where he pointed out that he wasn't aware of any
other language that did overloading this way.
I don't see that as an advantage - I see it as a positive disadvantage.
It means that everyone has to read the specification in considerable
detail in order to be able to predict what their code will do.

Not only have I never found anyone who would intuitively expect the
current behaviour - I haven't found anyone who worked out why it was on
their first trawl through the spec, either. It always takes a very
careful analysis to find out what should actually happen. (It took me
ages first time.)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 27 '07 #13
On Tue, 27 Mar 2007 07:29:38 +0100, Jon Skeet [C# MVP]
<sk***@pobox.comwrote:
>I don't see that as an advantage - I see it as a positive disadvantage.
It means that everyone has to read the specification in considerable
detail in order to be able to predict what their code will do.
I would agree, but framework versioning is apparently the highest
priority for the CLR team. I once submitted a similar request to
change the overload resolution of generic methods (non-generic base
class methods are ignored if a matching generic derived method is
found), and I got the same reply:

https://connect.microsoft.com/Visual...edbackID=92075

"The reason we 'stop the search' in the current type is because of
versioning. If we didn't, then it would be possible for someone to add
a method in the base class and suddenly the code that was behaving one
way, will start to do something different because the new method will
be called. This is a variant of the fragile base class problem."
--
http://www.kynosarges.de
Mar 27 '07 #14
AJ
In article <MP************************@msnews.microsoft.com >,
sk***@pobox.com says...
Barry Kelly <ba***********@gmail.comwrote:
Jon Skeet [C# MVP] wrote:
Because the spec is very, very weird when it comes to overloading.
It's actually with good reason: it makes it safe to add new overloads to
base classes in the framework without worrying that existing programs
are going to break when recompiled, due to finding the new overload when
the new framework is released.

That's a reasonable point - but I still find it counterintuitive, and
it seems that others do too.
I'm still not convinced that it's the 'right' decision, nor that the
spec really explains it that well (if at all..)

However, if you're all suggesting that the behaviour is correct, then
the IDE has a bug - the intellisense displays the two overloads as
options where, in my example, I don't think that the Add(byte) method is
_ever_ going to get called, since the byte will always get promoted to
an int..
Mar 27 '07 #15

"Barry Kelly" <ba***********@gmail.comwrote in message
news:jj********************************@4ax.com...
Jon Skeet [C# MVP] wrote:
>The output, contrary to intuitive expectations, is
"Derived.Foo(object)".

It's bonkers if you ask me, but that's what the spec says...

Whups - I do agree with you about the overridden version though, it
shouldn't remove overridden overloads, as that's evidence that the
descendant is aware of the ancestor's method.
And as nearly as I can tell, that's how C++ works -- you can't overload a
base member function, you end up overriding, but your own overrides of base
functions are also considered.
Mar 30 '07 #16

This discussion thread is closed

Replies have been disabled for this discussion.

By using this site, you agree to our Privacy Policy and Terms of Use.