No Equals on interfaces

M

Michi Henning

Hi,

the following code won't compile, but I believe it should:

Interface X
End Interface

Module M
Sub Main(ByVal args As String())
Dim iref As X
iref.Equals(iref) ' 'Equals' is not a member of 'vb.I'.
End Sub
End Module

The compiler complains that X does not have a member Equals.
(The same complaint is issued for the other methods of System.Object:
GetHashCode, GetType, and ToString.)

This seems wrong, given that C# compiles the equivalent code
without complaint.

Also, the following works fine:

Dim iref As X
Dim oref As Object = iref
oref.Equals(oref)

Clearly, if there is an implicit conversion from X to Object,
then X must have the members of Object (otherwise, implicit
conversion would have to be illegal.)

Does anyone know whether this problem is fixed for Whidbey?

Thanks,

Michi.
 
T

Tom Dacon

Simple: interfaces don't, and can't, inherit from Object (see the MSDN
documentation on interfaces). If they inherit from anything, it can only be
another interface.

Also, C# does not compile the equivalent code* without complaint. It
complains, quite rightly in my opinion, that you can't create an instance of
the abstract class X. Of course, if you create a concrete class which
implements X, the class itself is derived from Object and consequently has
all the members that Object provides.

Tom Dacon
Dacon Software Consulting

* The equivalent C# code, as I take it, would be:

X iref = new X();
iref.Equals(iref);
 
M

Michi Henning

Tom said:
Simple: interfaces don't, and can't, inherit from Object (see the MSDN
documentation on interfaces). If they inherit from anything, it can only be
another interface.

Really? Hmmm... X is a reference type. All reference types implicitly inherit
from System.Object, last time I looked.
Also, C# does not compile the equivalent code* without complaint. It
complains, quite rightly in my opinion, that you can't create an instance of
the abstract class X.

It seems that you missed that the code I posted never instantiates X.
Of course, if you create a concrete class which
implements X, the class itself is derived from Object and consequently has
all the members that Object provides.

I'm not talking about classes here, but interfaces.
* The equivalent C# code, as I take it, would be:

X iref = new X();
iref.Equals(iref);

No. The equivalent C# code is:

public interface X {}

class M
{
static void Main(string[] args)
{
X iref = null;
iref.Equals(iref);
}
}

And that code compiles just fine, as it should.


Michi.

http://www.triodia.com/staff/michi
 
C

Cor Ligthert

Michi,

Is this the result you want to reach?

If iref Is iref Then
End If

Cor
 
H

Herfried K. Wagner [MVP]

* Michi Henning said:
Really? Hmmm... X is a reference type. All reference types implicitly inherit
from System.Object, last time I looked.

That's not true for interfaces. Interfaces can only inherit from other
interfaces and not from classes, and thus don't derive from 'Object'
which is a class.
* The equivalent C# code, as I take it, would be:
X iref = new X();
iref.Equals(iref);

No. The equivalent C# code is:

public interface X {}

class M
{
static void Main(string[] args)
{
X iref = null;
iref.Equals(iref);
}
}

And that code compiles just fine, as it should.

The code below compiles in VB.NET too, but it will throw a
'NullReferenceException' at runtime:

\\\
Dim Foo As IFoo
MsgBox(Foo.Equals(Foo))
..
..
..
Public Interface IFoo
Function Equals(ByVal Foo As IFoo) As Boolean
End Interface
///
 
H

Herfried K. Wagner [MVP]

* Michi Henning said:
the following code won't compile, but I believe it should:

Interface X
End Interface

Module M
Sub Main(ByVal args As String())
Dim iref As X
iref.Equals(iref) ' 'Equals' is not a member of 'vb.I'.
End Sub
End Module

The compiler complains that X does not have a member Equals.
(The same complaint is issued for the other methods of System.Object:
GetHashCode, GetType, and ToString.)

This seems wrong, given that C# compiles the equivalent code
without complaint.

That's simply different behavior in C# and VB.NET, and I think that the
behavior shown by VB.NET is more correct. Interfaces in .NET do /not/
have a base type if they don't inherit from another interface.

In C#, the compiler doesn't complain for some reason, but the code you
listed above is rather useless because it will throw a
'NullReferenceException'. None of the methods you can access from C#
are useful because they are all instance members and interfaces cannot
be instantiated.
Also, the following works fine:

Dim iref As X
Dim oref As Object = iref
oref.Equals(oref)

Clearly, if there is an implicit conversion from X to Object,
then X must have the members of Object (otherwise, implicit
conversion would have to be illegal.)

Does anyone know whether this problem is fixed for Whidbey?

There is no problem in VB.NET. It's IMO a C# problem.
 
J

Jay B. Harlow [MVP - Outlook]

Michi,
Whidbey has not fixed either C# nor VB.NET that I have seen.

C# needs to be fixed as it thinks Interfaces inherit from Object. Interfaces
cannot inherit from a Class! Your Interface X does not have Inherit Object
implicitly in its definition. C# just makes it appear that it does.

VB.NET needs to be fixed is it thinks that an object (the thing that
implemented the Interface) does not inherit from Object. It is a valid
assertion as Interface X does not implicitly nor explicitly inherit from
System.Object.

Which is correct & which is wrong is an age old debate. For the most part I
think VB.NET is correct, as Interfaces cannot inherit from a Class, however
I can see C#'s pov as every thing is an object!

IMHO it gets even stickier when we start using Generics in Whidbey, as IMHO
the generic parameter implicitly is constrained by object.

Hope this helps
Jay
 
D

David

That's simply different behavior in C# and VB.NET, and I think that the
behavior shown by VB.NET is more correct. Interfaces in .NET do /not/
have a base type if they don't inherit from another interface.

In C#, the compiler doesn't complain for some reason, but the code you
listed above is rather useless because it will throw a
'NullReferenceException'.

True, but the same concept applies if we change iref to a parameter

Public Sub foo(byval iref As X)
If iref.Equals(myXReference) Then ...

The Null reference is a problem for the posted example, but it's
irrelevant to the general concept.
None of the methods you can access from C#
are useful because they are all instance members and interfaces cannot
be instantiated.

I'm not sure I understand what you're saying here. C# interprets iref
above as being an instance of some sub-type of Object that also
implements X. Whatever else iref may be, we know that it's a
System.Object, and therefore the methods of System.Object are available.

I'm not sure what you mean when you say these methods aren't useful. Why
not?
 
H

Herfried K. Wagner [MVP]

* David said:
True, but the same concept applies if we change iref to a parameter

Public Sub foo(byval iref As X)
If iref.Equals(myXReference) Then ...

The Null reference is a problem for the posted example, but it's
irrelevant to the general concept.

Mhm... In VB.NET, I would cast explicitly to 'Object' to access the
properties/methods exposed by C# directly:

\\\
Dim foo As IFoo
Dim b As Boolean = CObj(foo).Equals(CObj(foo))
..
..
..
Public Interface IFoo
'
End Interface
///
I'm not sure I understand what you're saying here. C# interprets iref
above as being an instance of some sub-type of Object that also
implements X. Whatever else iref may be, we know that it's a
System.Object, and therefore the methods of System.Object are available.

I'm not sure what you mean when you say these methods aren't useful. Why
not?

The OP's sample IMO didn't make sense. The methods are useful in
matters of objects/classes, but not in matters of interfaces only, as
shown in the OP's sample. Providing the methods of the 'Object' class
waters down the semantics of interfaces because interfaces do not
provide these methods.

I often hear people complaining about VB making shared members available
through instance variables. That complies with VB.NET's semantic of
shared variables. Externalizing members defined in a type that is not a
subtype of the type a variable is declared in is against the semantics
of interfaces/variables.

I agree that the way this issue is handled in C# will make code shorter,
but it will make understanding the conduct made by an interface harder
to understand. It's not the only case where VB.NET is more explicit
than C#.
 
D

David

The OP's sample IMO didn't make sense. The methods are useful in
matters of objects/classes, but not in matters of interfaces only, as
shown in the OP's sample.

The word "useful" still seems out of place here, but I see the point
you're getting at.
Providing the methods of the 'Object' class
waters down the semantics of interfaces because interfaces do not
provide these methods.

Hmmm. I must admit, I don't really have much of a preference one way or
another. I can't really think of a way that either could lead to error,
and that's the only real measure of these things to me.

What's interesting (to me, at least) is that the C# way makes a bit
more sense to me, and I'm more of a C# than VB programmer, but the more
ardent VB defenders here greatly prefer the VB way. I don't think
that's just language partisanship, it makes me think that the designers
chose correctly here, and the choices reflect some underlying themes of
the two languages.

I only have very vague and ambiguous ideas on what those themes are,
though. VB does tend to treat variable names and declarations as more
important entities than does C#. I'm thinking of the way that implicit
events bind to variable names and not to objects in VB, while in C# the
variable is simply front-end syntax representing a real object. In this
case, to c# everything is an instance of some class and therefore an
object, while to VB the underlying object is ignored in favor of the
immediate declaration. (Or not, like I said, thematic consistency is a
huge and deep topic and I haven't really thought it through).

[And for the flamers here, don't bother. I'm not dissing VB at all
here, I just find it interesting how different languages and those who
use them look at these things differently]
I often hear people complaining about VB making shared members available
through instance variables. That complies with VB.NET's semantic of
i> shared variables.

Yeah, I'd be one of the people complaining. I think that was a horrible
decision, but that's neither here nor there.
 
H

Herfried K. Wagner [MVP]

* David said:
The word "useful" still seems out of place here, but I see the point
you're getting at.

OK.

It's interesting that C#'s object browser lists 'Object' as base class
for interfaces which is definitely not true and thus misleading. So,
it's actually C# that puts a semantic on interfaces that differs from the
semantics put on them in general .NET terminology. Interfaces are no
classes, and C# wants to tell me that they are, because interfaces
cannot inherit from a class ('Object' in this case).

(Just to make that clear: I respect that C# uses a different way to
handle interfaces, and I think it's good that there are many differences
between C# and VB.NET. But personally, I don't like the solution taken
by C#.)
Hmmm. I must admit, I don't really have much of a preference one way or
another. I can't really think of a way that either could lead to error,
and that's the only real measure of these things to me.
:)

What's interesting (to me, at least) is that the C# way makes a bit
more sense to me, and I'm more of a C# than VB programmer, but the more
ardent VB defenders here greatly prefer the VB way. I don't think
that's just language partisanship, it makes me think that the designers
chose correctly here, and the choices reflect some underlying themes of
the two languages.

Full ACK! There are certain cases where I like the way C# handes things
better, but in this case, I vote for the VB.NET solution. Nevertheless
I can understand the thought behind the C# way, "Every variable holds a
reference to an object or a null reference, thus the members provided by
the 'Object' class should be available for every variable". That's not
a bad idea, but it shows that for C#ies the /variable/ has other
semantics than in VB.NET, and that variables are more important than
general definitions of "interface" and "class".
I only have very vague and ambiguous ideas on what those themes are,
though. VB does tend to treat variable names and declarations as more
important entities than does C#. I'm thinking of the way that implicit
events bind to variable names and not to objects in VB

Do they? There is nothing implicit for events in VB. You will have to
use 'AddHandler' or 'RemoveHandler' which is very similar to the
approach taken in C#, or use 'WithEvents' + 'Handles' which is
declarative, but not implicit.
while in C# the variable is simply front-end syntax representing a
real object. In this case, to c# everything is an instance of some
class and therefore an object, while to VB the underlying object is
ignored in favor of the immediate declaration.

That's true.
Yeah, I'd be one of the people complaining. I think that was a horrible
decision, but that's neither here nor there.

I like the decision because I think it perfectly fits into the VB.NET
language. I would not like that to work in C#. C# and VB.NET are for
different people...
 
D

David

It's interesting that C#'s object browser lists 'Object' as base class
for interfaces which is definitely not true and thus misleading.

I don't disagree there, but I also don't consider the object browser
part of the language. Actually, I so seldom open the object browser
that I don't really have an opinion at all on whether the browser should
show usage or abstractions. I wonder if that's another common
difference between C# and VB developers?
So,
it's actually C# that puts a semantic on interfaces that differs from the
semantics put on them in general .NET terminology. Interfaces are no
classes, and C# wants to tell me that they are, because interfaces
cannot inherit from a class ('Object' in this case).

On the flip side, c# follows IL semantics here. You don't need a cast
in IL in this situation either. This is often true of differences in
the languages, C# tends to be closer to IL and the CLR.
(Just to make that clear: I respect that C# uses a different way to
handle interfaces, and I think it's good that there are many differences
between C# and VB.NET. But personally, I don't like the solution taken
by C#.)

ACK (except for the personal preference :)

Full ACK! There are certain cases where I like the way C# handes things
better, but in this case, I vote for the VB.NET solution. Nevertheless
I can understand the thought behind the C# way, "Every variable holds a
reference to an object or a null reference, thus the members provided by
the 'Object' class should be available for every variable". That's not
a bad idea, but it shows that for C#ies the /variable/ has other
semantics than in VB.NET, and that variables are more important than
general definitions of "interface" and "class".

I see the C# decision here slightly differently. I think it has
something to do with the tendency of c/c++ developers to think of
language artifacts as being thin artificial layers over the "real"
objects. I mentioned before in another thread with you that when I see
virtual or Overridable, I immediately think of an actual vtable. I
think that's common among certain developers. When I see...

Public Sub (someVar as ISomeInterface)

I don't think someVar is an ISomeInterface, because such a thing can't
exist in the CLR (I even struggled on what to call it here: an
ISomeInterface instance, an ISomeInterface object, an ISomeInterface
entity?). Rather, I think of it as a reference to an instance of some
Object-derived class that implements ISomeInterface, and therefore it's
natural that this reference contains an Object vtable.

My difference with your construction above is I don't think I'd say that
"every variable holds..." when describing the difference here. I don't
think of variables as doing things, they're mere signifiers (where's
Umberto Eco when you really need him :).

Again, just a different way of looking at things, and a different
language for modelling things, and I don't think one is objectively
better than the other.
Do they? There is nothing implicit for events in VB. You will have to
use 'AddHandler' or 'RemoveHandler' which is very similar to the
approach taken in C#, or use 'WithEvents' + 'Handles' which is
declarative, but not implicit.

You're right, declarative is the correct term. The fact that assigning
an object reference to a variable changes the state of the object that
the variable used to reference took me a long while to get my head
around. It's just not how I think of variable names working. Even
today I don't really *get* it, I just think of the underlying IL as my
model to understand what's going on.

I like the decision because I think it perfectly fits into the VB.NET
language.

Out of curiosity, how so?

My complaint with accessing shared members and fields through instance
variables isn't that it's confusing or inconsistent, but rather that
it's error prone. But this issue is well-trodden ground where the pros
and cons have been hashed out pretty thoroughly over many years and many
languages.
 
C

Cor Ligthert

Herfried,

Do you know what is so nice, when you compile the both samples you get
exactly the same error. Not that I was in doubt of that of course after your
full complete explananion.

:)

I changed the VB statement to Directcast(iref,object).Equals.iref

:)

Cor
 
H

Herfried K. Wagner [MVP]

David,

* David said:
I don't disagree there, but I also don't consider the object browser
part of the language.

I agree, the object browser is not part of the language. But the
different behavior of the object browser shows us that this is not
erroneous hehavior in VB.NET or C# that was not intended by the language
teams.
Actually, I so seldom open the object browser
that I don't really have an opinion at all on whether the browser should
show usage or abstractions. I wonder if that's another common
difference between C# and VB developers?

I often use the object browser to check an object's methods and
properties or search for a member, because it's faster than bringing up
the MSDN library.
On the flip side, c# follows IL semantics here. You don't need a cast
in IL in this situation either. This is often true of differences in
the languages, C# tends to be closer to IL and the CLR.

I work with both, VB.NET and C#, but I only want speak from a VB.NET
point of view. That's why I said that how interfaces are handled in
VB.NET is closer to the idea of an interface. For me, always interfaces
are not seen as "objects", or entities that can exist. I see them more
as a contract that has nothing to do with objects at all. Objects can
agree with this contract by implementing a specific interface. Still,
the interface has nothing to do with the object. There is no guarantee
that there will ever exist subclasses to an interface (sure, an
interface that is never implemented or inherited from is rather
useless).

Maybe I see interfaces more "abstract" than you do. I don't care much
about implementation details. Implementation details can change and
should not influence the whole (abstract) concept. Note that this
doesn't mean that implementation details are interesting too, but that's
another discussion. VB programmers IMO see more things as black boxes
or more abstract than C* programmers do. I assume that this is caused
by the different background C* and *Basic programmers are coming from.
I see the C# decision here slightly differently. I think it has
something to do with the tendency of c/c++ developers to think of
language artifacts as being thin artificial layers over the "real"
objects. I mentioned before in another thread with you that when I see
virtual or Overridable, I immediately think of an actual vtable. I
think that's common among certain developers. When I see...

Public Sub (someVar as ISomeInterface)

I don't think someVar is an ISomeInterface, because such a thing can't
exist in the CLR (I even struggled on what to call it here: an
ISomeInterface instance, an ISomeInterface object, an ISomeInterface
entity?).

I see the procedure head above as this: 'someVar' contains a reference to
an object that has accepted the contract called 'ISomeInterface'. So,
it's not an 'ISomeInterface' instance/object/ entitiy. Being an
'ISomeInterface' is a "property" of an object that an object can have or
not.
Rather, I think of it as a reference to an instance of some
Object-derived class that implements ISomeInterface, and therefore it's
natural that this reference contains an Object vtable.

ACK again. Nevertheless, this is not as important to me as the contract
made by an interface. When thinking of interfaces, I hardly ever thing
of a class that derives from 'Object' and implemements
'ISomeInterface'. Instead, I think of classes that agree with the
contract given by 'ISomeInterface' only. I think this is a more
abstract view on interfaces (which doesn't mean that it's necessarily
better).
My difference with your construction above is I don't think I'd say that
"every variable holds..." when describing the difference here. I don't
think of variables as doing things, they're mere signifiers (where's
Umberto Eco when you really need him :).

I don't need Umberto Eco here, but I know about his theories... :).
Again, just a different way of looking at things, and a different
language for modelling things, and I don't think one is objectively
better than the other.

ACK. It's more important to see if one of the ways of looking at things
is more error-prone than the other.
Out of curiosity, how so?

I have written that several times in this group and I didn't want to
move the discussion onto this topic, so I'll say only a few words: The
VB team has chosen the keyword 'Shared', and for me, the meaning of
shared is that a member belongs to /all/ instances of a class. So it
would be a contradiction to the keyword's name if access to these
members is not allowed.
My complaint with accessing shared members and fields through instance
variables isn't that it's confusing or inconsistent, but rather that
it's error prone. But this issue is well-trodden ground where the pros
and cons have been hashed out pretty thoroughly over many years and many
languages.

ACK.
 
D

David

David,

* David <[email protected]> scripsit:
I work with both, VB.NET and C#, but I only want speak from a VB.NET
point of view. That's why I said that how interfaces are handled in
VB.NET is closer to the idea of an interface. For me, always interfaces
are not seen as "objects", or entities that can exist. I see them more
as a contract that has nothing to do with objects at all. Objects can
agree with this contract by implementing a specific interface. Still,
the interface has nothing to do with the object. There is no guarantee
that there will ever exist subclasses to an interface (sure, an
interface that is never implemented or inherited from is rather
useless).

Maybe I see interfaces more "abstract" than you do. I don't care much
about implementation details. Implementation details can change and
should not influence the whole (abstract) concept. Note that this
doesn't mean that implementation details are interesting too, but that's
another discussion. VB programmers IMO see more things as black boxes
or more abstract than C* programmers do. I assume that this is caused
by the different background C* and *Basic programmers are coming from.

I think there's some truth to that. In VB there is often another layer
of abstraction within the language. Language signifiers in C# are just
that, signifiers for runtime entities. But in VB compile-time entities
like variable names really do matter at runtime, as in the event example
I mentioned. VB had a long history of this, with things such as the
class/instance blurring with VB forms or even, in a more general sense,
returning a result by assigning to the Function name.

Then we have words like "interface", which can represent c# keyword, a
vb.net keyword, an IL keyword, a CLR entity, and a general .Net concept,
all with slightly different definitions.
I have written that several times in this group and I didn't want to
move the discussion onto this topic, so I'll say only a few words: The
VB team has chosen the keyword 'Shared', and for me, the meaning of
shared is that a member belongs to /all/ instances of a class. So it
would be a contradiction to the keyword's name if access to these
members is not allowed.

Okay. Like I said, I didn't want to get into the pros and cons here.
 
H

Herfried K. Wagner [MVP]

* David said:
I think there's some truth to that. In VB there is often another layer
of abstraction within the language. Language signifiers in C# are just
that, signifiers for runtime entities. But in VB compile-time entities
like variable names really do matter at runtime, as in the event example
I mentioned. VB had a long history of this, with things such as the
class/instance blurring with VB forms or even, in a more general sense,
returning a result by assigning to the Function name.

Then we have words like "interface", which can represent c# keyword, a
vb.net keyword, an IL keyword, a CLR entity, and a general .Net concept,
all with slightly different definitions.

Full ACK!
 
M

Michi Henning

Herfried K. Wagner said:
Then you are passing an instance of a class that inherits from
'Object'. The fact that instances of classes that implement interfaces
inherit from 'Object' is not due to implementing an interface, but by
inheriting from another class or (implicitly) 'System.Object'.

Sorry, I have to disagree. If a method has a formal parameter of type I,
then the compiler can generally not figure out at compile time whether
the reference I will pass to the method at run time will or will not
be to a class instance. The compiler must make a decision at compile
time as to whether to permit the express iref.Equals(...) or not, and it
can do make that decision only based on the formal parameter type.
That's true. But it has nothing to do with the concept of interfaces in
the VB.NET programming language.

If *all* references support the methods on type object, why is it then
that I cannot say "iref.Equals"? After all, a reference to an I is a reference.
That's because of the explicit nature of the VB.NET programming
language. Cast to 'Object' explicitly and the compile time error goes
away.

So, in one case, I have to explicitly cast to Object in order to invoke Equals
(the case I showed), but in another case I don't have to cast explicitly
(namely,
when I assign iref to oref). If the compiler stops from doing one, it should
stop
me from doing the other; or it should allow both. Doing it for one case but not
the other is inconsistent and, moreover, violates the words in the language
specification.

Michi.
 
M

Michi Henning

Herfried K. Wagner said:
The C# language specification doesn't apply to VB.NET. So your
statement is nonsense if you expect the same behavior from VB.NET or
simply out of context.

Ahem -- the VB language specification says the same thing.
Can you point me to the chapter talking about this behavior?

See my other post where I quoted the URL.

Michi.
 

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