interface mapping

G

Guest

Hi all

I wonder if the Microsoft C# compiler performs interface mapping according to the C# language specification (ECMA-334, 2nd edition December 2002)
Take a look at the following example

interface

int Foo { get; set;


class BaseClas

public int Fo

get { return 0;
set {



class DerivedClass: BaseClass,

public new int Fo

get { return 0;



Now let us locate the implementation for I.Foo. According to the language specification (section 20.4.2 Interface mapping), DerivedClass.Foo doesn't match I.Foo because DerivedClass.Foo doesn't have a set accessor. So the search for a matching implementation continues in BaseClass. Because BaseClass.Foo matches I.Foo, we are done

But to my surprise, running the compiler gives the following error
'DerivedClass' does not implement interface member 'I.Foo.set
(Note: if DerivedClass.Foo is removed, the program compiles without errors.

I've found other similar issues, but first I'd like to get your input on this one
Any comments would be greatly appreciated

Regards
pn
 
C

Chris A. R.

What's surprising about this? You're using "new" in
public new int Foo
which hides the BaseClass Foo. Therefore, your derived class does not have
access to your set in Foo.

Chris A.R.

pn said:
Hi all,

I wonder if the Microsoft C# compiler performs interface mapping according
to the C# language specification (ECMA-334, 2nd edition December 2002).
Take a look at the following example:

interface I
{
int Foo { get; set; }
}

class BaseClass
{
public int Foo
{
get { return 0; }
set {}
}
}

class DerivedClass: BaseClass, I
{
public new int Foo
{
get { return 0; }
}
}

Now let us locate the implementation for I.Foo. According to the language
specification (section 20.4.2 Interface mapping), DerivedClass.Foo doesn't
match I.Foo because DerivedClass.Foo doesn't have a set accessor. So the
search for a matching implementation continues in BaseClass. Because
BaseClass.Foo matches I.Foo, we are done.
 
G

Guest

I don't think it's as simple as that. Hiding an inherited member doesn't make it inaccessible

DerivedClass derived = new DerivedClass()
int i = ((BaseClass)derived).Foo; // invokes BaseClass.Fo

By the way, the new modifier doesn't have any effect on the semantics of a member declaration. It's just a way to explicitely state that a newly introduced member hides an inherited member. If you leave it out, you'll get a compiler warning, but the program will behave the same


----- Chris A. R. wrote: ----

What's surprising about this? You're using "new" i
public new int Fo
which hides the BaseClass Foo. Therefore, your derived class does not hav
access to your set in Foo

Chris A.R

pn said:
to the C# language specification (ECMA-334, 2nd edition December 2002)
Take a look at the following example

int Foo { get; set;


public int Fo

get { return 0;
set {



public new int Fo

get { return 0;
specification (section 20.4.2 Interface mapping), DerivedClass.Foo doesn'
match I.Foo because DerivedClass.Foo doesn't have a set accessor. So th
search for a matching implementation continues in BaseClass. Becaus
BaseClass.Foo matches I.Foo, we are done
 
C

Chris A. R.

Remove the interface from DerivedClass:
class DerivedClass: BaseClass

And then try this code:
DerivedClass derived = new DerivedClass();
derived.Foo = derived.Foo;

You'll see that it fails, because it cannot be assigned to, since you
haven't defined a 'set'. That's why, when you use the interface, it
complains.

if you use
((BaseClass)derived).Foo = ((BaseClass)derived).Foo;
it'll compile just fine.

So, everything works as defined and as expected.
When you create a "new" member, it really is NEW. derived.Foo and
((BaseClass)derived).Foo do not refer to the same property. You can
manipulate the values totally independent of each other, if you so desire
to.

It's that simple.

Chris A.R.

pn said:
I don't think it's as simple as that. Hiding an inherited member doesn't make it inaccessible:

DerivedClass derived = new DerivedClass();
int i = ((BaseClass)derived).Foo; // invokes BaseClass.Foo

By the way, the new modifier doesn't have any effect on the semantics of a
member declaration. It's just a way to explicitely state that a newly
introduced member hides an inherited member. If you leave it out, you'll get
a compiler warning, but the program will behave the same.
 
C

Chris A. R.

pn

Name hiding is absolutely relevant.

Given:
interface I
{
int Foo { get; set; }
}

The DerivedClass in
class DerivedClass: BaseClass, I

MUST have access to both the 'get' and 'set' to be considered to have
successfully mapped the interface. Whey you hide BaseClass memembers, they
no longer are participate in DerivedClass, and therefore do not participate
in the mapping of the I interface.

Just because the algorithm doesn't mention name hiding, the concept of name
hiding itself is clear in 10.7.1 discussing the scope visibility of class
members. A method must be visible/in scope in a class to satisfy name
mapping.

Chris A.R.

pn said:
Thanks for your response. I think we are at cross-purposes. Everything you
write is completely clear to me. What I don't understand is WHY I.Foo gets
mapped to DerivedClass.Foo. According to the interface mapping algorithm
(section 20.4.2 interface mapping) it should get mapped to BaseClass.Foo,
because BaseClass.Foo (but NOT DerivedClass.Foo) matches I.Foo. (Take a look
at the definition of 'class member matches interface member'.
DerivedClass.Foo doesn't match I.Foo because it lacks a set accessor.) The
algorithm doesn't say anything related to name hiding, so I don't think this
is relevant.
 
R

Richard A. Lowe

pn, look at it as the answer to this question: Does DerivedClass, in any
scope, satisfy the requirements to implement interface "I"?

You may currently be inclined to say the answer is "yes" because up the
inheretance chain one one step BaseClass fulfills what "I" needs. However,
consider what the "new" modifier means. When used in a derived class, it's
*completely eliminating the base member from itself*. No DerivedClass
reference, regardless what scope you have access to, will ever have a setter
on Foo. The "base" keyword can get you access, but the base keyword is a
reference type of the base type, not DerivedClass. So "I" requires a setter
on Foo, DerivedClass has no setter on Foo.

I hope that makes some further sense.
Richard
--
C#, .NET and Complex Adaptive Systems:
http://blogs.geekdojo.net/Richard
pn said:
Thanks for your response. I think we are at cross-purposes. Everything you
write is completely clear to me. What I don't understand is WHY I.Foo gets
mapped to DerivedClass.Foo. According to the interface mapping algorithm
(section 20.4.2 interface mapping) it should get mapped to BaseClass.Foo,
because BaseClass.Foo (but NOT DerivedClass.Foo) matches I.Foo. (Take a look
at the definition of 'class member matches interface member'.
DerivedClass.Foo doesn't match I.Foo because it lacks a set accessor.) The
algorithm doesn't say anything related to name hiding, so I don't think this
is relevant.
 
G

Guest

----- Richard A. Lowe wrote: -----
However, consider what the "new" modifier means. When used in a derived class, it'
*completely eliminating the base member from itself*.

As I said before, while the new modifier has a meaning to us programmers, it doesn't have any meaning to the program. It merely suppresses a compiler warning that would have otherwise occured
Also, the hidden base class memberisn't "completely eliminated" from the derived class. Quite on the contrary, EVERY customer of DerivedClass can invoke the hidden member simply by upcasting
int i = ((BaseClass)derived).Foo; // invokes BaseClass.Fo
Maybe this is a good point to clear up the difference between hiding and overriding an inherited member: a hidden member is still present in the derived class (in the sense that it can be invoked). An overridden (virtual) member is no longer present, and can only be invoked from inside the derived class (using the base keyword)
No DerivedClas
reference, regardless what scope you have access to, will ever have a sette
on Foo. The "base" keyword can get you access, but the base keyword is
reference type of the base type, not DerivedClass.

Depends on what you mean by "DerivedClass reference". If you mean a reference typed as DerivedClass, I'll agree. If you mean a reference to an object of type DerivedClass, this is not true

Regards
pn
 
G

Guest

----- Chris A. R. wrote: -----
Name hiding is absolutely relevant
...
Whey you hide BaseClass memembers, the
no longer are participate in DerivedClass, and therefore do not participat
in the mapping of the I interface

I can see no reason why hidden members don't "participate" in interface mapping. The algorithm considers every member DECLARATION, starting from DerivedClass and walking up the inheritance chain. Eventually, it will arive at the class where the member that is hidden in DerivedClass was declared. As you can see, name hiding has no effect on this process
A method must be visible/in scope in a class to satisfy name mapping
Where do you take that from? We're not talking about one's own beliefs, but about the correctness of an implementation with regards to a semi-formal specification

Regards
p
 
R

Richard A. Lowe

while the new modifier has a meaning to us programmers, it doesn't have
any meaning to the program.

It at very least has meaning to the compiler when attaching an interface to
the class, which is why your scenario doesn't work (but you already know
this!).
Also, the hidden base class memberisn't "completely eliminated" from the
derived class. Quite on the contrary, EVERY customer of DerivedClass can >
invoke the hidden member simply by upcasting:

Then you don't have a reference to a DerivedClass, you have a reference to
BaseClass; My meaning is that the "conceptual entity" that is
"DerivedClass" can, in fact, do away with Foo as defined in BaseClass.
Certainly you are correct that an object constructed with the default ctor
of DerivedClass does get, vis-a-vis inheritance, a Foo with a setter when
case to BaseClass.
Depends on what you mean by "DerivedClass reference". If you mean a
reference typed as DerivedClass, I'll agree. If you mean a reference to an
object of type DerivedClass, this is not true.

As per the above, yup I meant a reference of type DerivedClass, so we are on
the same page there.

Cheers,
Richard

--
C#, .NET and Complex Adaptive Systems:
http://blogs.geekdojo.net/Richard
pn said:
----- Richard A. Lowe wrote: -----

As I said before, while the new modifier has a meaning to us programmers,
it doesn't have any meaning to the program. It merely suppresses a compiler
warning that would have otherwise occured.
Also, the hidden base class memberisn't "completely eliminated" from the
derived class. Quite on the contrary, EVERY customer of DerivedClass can
invoke the hidden member simply by upcasting:
int i = ((BaseClass)derived).Foo; // invokes BaseClass.Foo
Maybe this is a good point to clear up the difference between hiding and
overriding an inherited member: a hidden member is still present in the
derived class (in the sense that it can be invoked). An overridden (virtual)
member is no longer present, and can only be invoked from inside the derived
class (using the base keyword).
Depends on what you mean by "DerivedClass reference". If you mean a
reference typed as DerivedClass, I'll agree. If you mean a reference to an
object of type DerivedClass, this is not true.
 
G

Guest

Meanwhile I've found a good way to "prove" that name hiding isn't the reason the compiler doesn't consider the base class member a valid match
Let's slightly modify our example code

interface

int Foo { get; set;


class BaseClass:

int I.Foo // explicit interface member implementatio

get { return 0;
set {



class DerivedClass: BaseClass,

public int Fo

get { return 0;



Clearly, DerivedClass.Foo does not hide any base class members (note that the compiler doesn't demand a new modifier). Nevertheless, the compiler still gives the same error

Regards
pn
 
R

Richard A. Lowe

No-one's claiming that BaseClass doesn't exist anymore, only that
DerivedClass changes BaseClass in a way that cannot fulfill the contract "I"
specifies. The point is a derived class can change the definition of a base
class and an interface will only "look at" either the explicitly defined
members of a class or it's *non-hidden* inherited members for implicit
fulfillment.

--
C#, .NET and Complex Adaptive Systems:
http://blogs.geekdojo.net/Richard
pn said:
Meanwhile I've found a good way to "prove" that name hiding isn't the
reason the compiler doesn't consider the base class member a valid match.
Let's slightly modify our example code:

interface I
{
int Foo { get; set; }
}

class BaseClass: I
{
int I.Foo // explicit interface member implementation
{
get { return 0; }
set {}
}
}

class DerivedClass: BaseClass, I
{
public int Foo
{
get { return 0; }
}
}

Clearly, DerivedClass.Foo does not hide any base class members (note that
the compiler doesn't demand a new modifier). Nevertheless, the compiler
still gives the same error.
 
G

Guest

while the new modifier has a meaning to us programmers, it doesn't hav
any meaning to the program
It at very least has meaning to the compiler when attaching an interface t
the class, which is why your scenario doesn't work (but you already kno
this!)

Please understand that the new modifier has NO EFFECT WHATSOEVER on the semantics of a program. Name hiding doesn't occur because of the new modifier. It occurs every time a member is declared that has the same name/signature as inherited members whose scope extends to the current class (for a more precise definition, see 10.7.1.2 Hiding through inheritance). The new modifier is just a way to tell the compiler that you know what you are doing (namely hiding one or more base class members). Leaving it out will give you a warning (the compiler says "do you know what you're doing?"), but the program will behave EXACTLY the same

Please have a look at my lastest response to Chris A. R. I think the example I give there proves that name hiding isn't the reason for the compiler's behaviour

Regards
pn
 
R

Richard A. Lowe

Okay, we aren't communicating on this issue, but I will suggest going here:
http://www.gotdotnet.com/Community/MessageBoard/MessageBoard.aspx?ID=5627
and posing the same question. Perhaps Eric Gunnerson will answer.

I do not dispute the effect of the new modifier, it just eliminates the
warning, true.... the point was about member hiding, though. Regardless of
how you get there (hiding the member in Derived) the Foo of the base type is
hidden, do you agree? Your example still shows that DerivedClass can't
implement "I". BaseClass implementing it has nothing to do with
DerivedClass implementing it.

What's frustrating here is that I feel there's still some information about
your perspective that I am not in possession of. To me it's as if you're
saying (and I'm not trying to be in any way derisive here, just trying to
plainly state what I hear, which may not quite reflect your view):

You: "This interface 'I' can't be implemented by my DerivedClass, but can be
by the base class"
Chris and I: "What's different about the DerivedClass"
You: "It hides a class member that participates in the interface definition"
Chris and I: "That's the reason: DerivedClass must not hide members that you
want to fulfill the interface contract"
You: "Member hiding is not the reason because the base class should fulfill
the contract"
Chris and I: "If nothing else is different, then *by definition* the member
hiding IS the only possibly reason. It's practically a tautology..."

Does that shed any light on our position? (sorry I probably shouldn't have
written "Chris" in there, I don't speak for him)

Richard "Just trying to understand..."

--
C#, .NET and Complex Adaptive Systems:
http://blogs.geekdojo.net/Richard
pn said:
any meaning to the program.


Please understand that the new modifier has NO EFFECT WHATSOEVER on the
semantics of a program. Name hiding doesn't occur because of the new
modifier. It occurs every time a member is declared that has the same
name/signature as inherited members whose scope extends to the current class
(for a more precise definition, see 10.7.1.2 Hiding through inheritance).
The new modifier is just a way to tell the compiler that you know what you
are doing (namely hiding one or more base class members). Leaving it out
will give you a warning (the compiler says "do you know what you're
doing?"), but the program will behave EXACTLY the same.
Please have a look at my lastest response to Chris A. R. I think the
example I give there proves that name hiding isn't the reason for the
compiler's behaviour.
 
R

Richard A. Lowe

Yeah, when it comes to the spec questions, it's good to go there. I'll just
watch the thread you started and see if you get any satisfaction to your
quandry.

R.

--
C#, .NET and Complex Adaptive Systems:
http://blogs.geekdojo.net/Richard
pn said:
Thanks a lot for pointing me to the gotdotnet message boards! I'll try to
answer your posting later this day, but first I must get some work done.
 
C

Chris A. R.

For:
interface I
{
int Foo { get; set; }
}

class BaseClass
{
public int Foo
{
get { return 0; }
set {}
}
}

class DerivedClass: BaseClass, I
{
public new int Foo
{
get { return 0; }
}
===========================

IL Code for BaseClass contains:

..property instance int32 Foo()
{
.get instance int32 TestProject.BaseClass::get_Foo()
.set instance void TestProject.BaseClass::set_Foo(int32)
} // end of property BaseClass::Foo

IL Code for DerivedClass contains:

..property instance int32 Foo()
{
.get instance int32 TestProject.DerivedClass::get_Foo()
} // end of property DerivedClass::Foo
===========================
These also contain the appropriate, corresponding definitions of the get and
set for the Foo properties.

When Derived looks for an implementations of the I interface, it finds the
Foo property is contained within Derived. The set and get are dependent
functions, described by the property. Therefore, since Foo is a property, it
must be examined at property level, NOT at a get and set level.

Since the property has been declared in Derived, that is as far as the
compiler needs to look. However, in this case, the .set instance int32
TestProject.Derived::set_Foo() method is not declared. This causes the
compile error.

Let me repeat: a property does not match by individual get and set methods,
but rather by the appropriate property as a whole. It is an all or nothing
contract which cannot be split between two different classes.

Chris A.R.

pn said:
Thanks a lot for pointing me to the gotdotnet message boards! I'll try to
answer your posting later this day, but first I must get some work done.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top