Google Groups Home Help | Sign in
Overloading in generic interfaces
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  24 messages - Collapse all
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
gleb.alex...@gmail.com  
View profile
 More options May 30 2007, 4:40 am
Newsgroups: microsoft.public.dotnet.languages.csharp
From: gleb.alex...@gmail.com
Date: 30 May 2007 01:40:32 -0700
Local: Wed, May 30 2007 4:40 am
Subject: Overloading in generic interfaces
Hello everyone!

It's my first post here.
Could anyone please explain me the behaviour of the following code?
<code>
    interface IFoo<T, P>
    {
        void Bar(T t, P p);        // (1)
        void Bar(P p1, P p2);   // (2)
    }

    class NastyFooImpl : IFoo<int, int>
    {
        void IFoo<int, int>.Bar(int t, int p)
        {
            Console.WriteLine("void IFoo<int, int>.Bar(int t, int
p)");
        }

        public void Bar(int p1, int p2)
        {
            Console.WriteLine("public void Bar(int p1, int p2)");
        }
    }

    class Program
    {
        static void Test<Foo, T, P> () where Foo : IFoo<T, P>, new()
        {
            Foo foo = new Foo();
            T t = default(T);
            P p = default(P);
            foo.Bar(t ,p);
            foo.Bar(p, p);
        }
        static void Main(string[] args)
        {
            Test<NastyFooImpl, int, int>();
        }
    }
</code>

The output I'm getting using Visual Studio 2005:
<code>
void IFoo<int, int>.Bar(int t, int p)
public void Bar(int p1, int p2)
</code>

When I swap lines (1) and (2), the order of lines of output changes as
well.
Any links are greatly appreciated, especially links to C#
specification.


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jon Skeet [C# MVP]  
View profile
 More options May 30 2007, 5:05 am
Newsgroups: microsoft.public.dotnet.languages.csharp
From: "Jon Skeet [C# MVP]" <sk...@pobox.com>
Date: 30 May 2007 02:05:48 -0700
Local: Wed, May 30 2007 5:05 am
Subject: Re: Overloading in generic interfaces
On May 30, 9:40 am, gleb.alex...@gmail.com wrote:

> It's my first post here.
> Could anyone please explain me the behaviour of the following code?

<snip>

Yowser, that's horrible!

I'll look at the spec closely tonight and see whether it helps.

The fact that (as you point out) the behaviour changes depending on
interface declaration order suggests something very nasty. It feels
like it shouldn't compile, but I wouldn't like to say exactly where ;)

Has this come up as an issue in production code? If so, regardless of
whether it's officially legal or what the compiler should really be
doing, I'd suggest trying to refactor things to avoid the situation -
you really don't want to have whoever reads the code next to have to
worry about it :)

Jon


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Marc Gravell  
View profile
 More options May 30 2007, 5:34 am
Newsgroups: microsoft.public.dotnet.languages.csharp
From: Marc Gravell <marc.grav...@gmail.com>
Date: 30 May 2007 02:34:31 -0700
Local: Wed, May 30 2007 5:34 am
Subject: Re: Overloading in generic interfaces
I'm not sure what you expect?

Overloading is determined at compile time, and for generics note that
the overloads are fixed in *generic* terms, not for specific types;

As such, given "T t" & "P p", the only match on Bar(t,p) is via
IFoo<T,P>.Bar(t, p), and the only match on Bar(p,p) is via
IFoo<T,P>.Bar(p1, p2); because this is decided early for *all* P, T,
there isn't any ambiguity here at all. If, however, you close the
generic sooner (to int, int), then there *would* be an ambiguity:

IFoo<int, int> foo = new NastyFooImpl();
foo.Bar(5,6); // which to call?

I believe the spec mentions a related case in particular, but I can't
find the reference. It was something like:
class SomeType<T> {
this[int index] {}
this[T key] {}

}

then refererring to SomeType<int> by an int indexer. IIRC the "index"
version wins over the "key" version because it checks non-generic
members first.

But as Jon said: yowser! Is this purely academic?

Marc


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Marc Gravell  
View profile
 More options May 30 2007, 5:41 am
Newsgroups: microsoft.public.dotnet.languages.csharp
From: Marc Gravell <marc.grav...@gmail.com>
Date: 30 May 2007 02:41:35 -0700
Local: Wed, May 30 2007 5:41 am
Subject: Re: Overloading in generic interfaces
Retraction; I misread the 2 lines that (when swapped) changed the
behaviour. It looks like some freakery in how the interface
implementation members are ticked off... very freaky! This looks very
much like an edge case, but very very curious. And one of the rare
occasions we get to talk about pure C# (rather than patterns, CLR,
etc) ;-p

Marc


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Christof Nordiek  
View profile
 More options May 30 2007, 6:01 am
Newsgroups: microsoft.public.dotnet.languages.csharp
From: "Christof Nordiek" <c...@nospam.de>
Date: Wed, 30 May 2007 12:01:34 +0200
Local: Wed, May 30 2007 6:01 am
Subject: Re: Overloading in generic interfaces
"Marc Gravell" <marc.grav...@gmail.com> schrieb im Newsbeitrag
news:1180517671.535033.289190@w5g2000hsg.googlegroups.com...

> I'm not sure what you expect?

> Overloading is determined at compile time, and for generics note that
> the overloads are fixed in *generic* terms, not for specific types;

But the example of the OP is about interface mapping.

> As such, given "T t" & "P p", the only match on Bar(t,p) is via
> IFoo<T,P>.Bar(t, p), and the only match on Bar(p,p) is via
> IFoo<T,P>.Bar(p1, p2); because this is decided early for *all* P, T,
> there isn't any ambiguity here at all. If, however, you close the
> generic sooner (to int, int), then there *would* be an ambiguity:

> IFoo<int, int> foo = new NastyFooImpl();
> foo.Bar(5,6); // which to call?

That is ambiguous and throws an compilererror.
None of the two members can be called on an expression of type IFoo<int,
int>.

> I believe the spec mentions a related case in particular, but I can't
> find the reference. It was something like:
> class SomeType<T> {
> this[int index] {}
> this[T key] {}
> }
> then refererring to SomeType<int> by an int indexer. IIRC the "index"
> version wins over the "key" version because it checks non-generic
> members first.

No, the call is ambiguous and results in a compiler error.

Christof


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Marc Gravell  
View profile
 More options May 30 2007, 6:14 am
Newsgroups: microsoft.public.dotnet.languages.csharp
From: Marc Gravell <marc.grav...@gmail.com>
Date: 30 May 2007 03:14:12 -0700
Local: Wed, May 30 2007 6:14 am
Subject: Re: Overloading in generic interfaces

> But the example of the OP is about interface mapping.

Yes, see my retraction; now, I don't claim to be a .Net king, but
I'm not a slouch either - and it threw me off the scent, which to
my mind is a warning sign "don't do this even if it does work" ;-p

[re similar case as cited]

> No, the call is ambiguous and results in a compiler error.

Not so; try this:

public class SomeDictionary<TKey> {
    public string this[int index] { get { return "index"; } }
    public string this[TKey key] { get { return "key"; } }

}

static class Program
{
    static void Main(string[] args)
    {
        SomeDictionary<int> wossit = new SomeDictionary<int>();
        string called = wossit[3]; // returns "index" as claimed
    }


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Marc Gravell  
View profile
 More options May 30 2007, 6:23 am
Newsgroups: microsoft.public.dotnet.languages.csharp
From: Marc Gravell <marc.grav...@gmail.com>
Date: 30 May 2007 03:23:49 -0700
Local: Wed, May 30 2007 6:23 am
Subject: Re: Overloading in generic interfaces

> Not so; try this:

ref ECMA 334, 3rd edtion; 14.4.2.2 Better function member

"If one of MP and MQ is non-generic, but the other is generic, then
the non-generic is better."


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
gleb.alex...@gmail.com  
View profile
 More options May 30 2007, 6:29 am
Newsgroups: microsoft.public.dotnet.languages.csharp
From: gleb.alex...@gmail.com
Date: 30 May 2007 03:29:44 -0700
Local: Wed, May 30 2007 6:29 am
Subject: Re: Overloading in generic interfaces
On May 30, 12:05 pm, "Jon Skeet [C# MVP]" <s...@pobox.com> wrote:

> Yowser, that's horrible!

I agree.

> I'll look at the spec closely tonight and see whether it helps.

Thanks, I'm looking forward to it.

> Has this come up as an issue in production code?

Well I have use-case for instantiating generic interface with equal
types, but I don't really need explicit interface implementation like
in the code snippet I posted. I've encountered this dark corner of the
language by accident. The purpose of this thread is to shed some light
on this issue, regardless of whether tricks like this should be used
in production.

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Marc Gravell  
View profile
(1 user)  More options May 30 2007, 6:50 am
Newsgroups: microsoft.public.dotnet.languages.csharp
From: Marc Gravell <marc.grav...@gmail.com>
Date: 30 May 2007 03:50:10 -0700
Local: Wed, May 30 2007 6:50 am
Subject: Re: Overloading in generic interfaces
I've looked at the spec. The way I read 20.4.2, this is possibly a
compiler bug, and "void IFoo<int, int>.Bar(int t, int p) " should
actually implement *both* IFoo methods. It certainly mentions nothing
about member sequence being significant. Generics don't mention any
real changes (25.3.2).

Marc


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Christof Nordiek  
View profile
(1 user)  More options May 30 2007, 6:50 am
Newsgroups: microsoft.public.dotnet.languages.csharp
From: "Christof Nordiek" <c...@nospam.de>
Date: Wed, 30 May 2007 12:50:11 +0200
Local: Wed, May 30 2007 6:50 am
Subject: Re: Overloading in generic interfaces
<gleb.alex...@gmail.com> schrieb im Newsbeitrag
news:1180514432.098377.282830@k79g2000hse.googlegroups.com...

> Hello everyone!

> It's my first post here.
> Could anyone please explain me the behaviour of the following code?
> <code>
>    interface IFoo<T, P>
>    {
>        void Bar(T t, P p);        // (1)
>        void Bar(P p1, P p2);   // (2)
>    }

This are possibly ambiguous members, they should be avoided but are
permitted

>    class NastyFooImpl : IFoo<int, int>
>    {
>        void IFoo<int, int>.Bar(int t, int p)
>        {
>            Console.WriteLine("void IFoo<int, int>.Bar(int t, int
> p)");
>        }

>        public void Bar(int p1, int p2)
>        {
>            Console.WriteLine("public void Bar(int p1, int p2)");
>        }
>    }

The question is, wich method implements wich interface member.
The first implementation fits for both. There doesn't seem to be a rule wich
permits one explicit interface implementation to be valid for two or more
member.
The second method also fits for both, but explicit interface implementations
take precedence over implicit interface implementations.
Both interface members should map on the first member.

>    class Program
>    {
>        static void Test<Foo, T, P> () where Foo : IFoo<T, P>, new()
>        {
>            Foo foo = new Foo();
>            T t = default(T);
>            P p = default(P);
>            foo.Bar(t ,p);
>            foo.Bar(p, p);

Here the both members are unambiguous. The first statement calls the first
member, the second calls the second member. Wich implementations are called
depends of the interface

>        }
>        static void Main(string[] args)
>        {
>            Test<NastyFooImpl, int, int>();
>        }
>    }
> </code>

> The output I'm getting using Visual Studio 2005:
> <code>
> void IFoo<int, int>.Bar(int t, int p)
> public void Bar(int p1, int p2)
> </code>

This would be a bug, since both should call the explicit implementation.

> When I swap lines (1) and (2), the order of lines of output changes as
> well.

Also a bug.

Christof


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Christof Nordiek  
View profile
 More options May 30 2007, 7:27 am
Newsgroups: microsoft.public.dotnet.languages.csharp
From: "Christof Nordiek" <c...@nospam.de>
Date: Wed, 30 May 2007 13:27:53 +0200
Local: Wed, May 30 2007 7:27 am
Subject: Re: Overloading in generic interfaces
"Marc Gravell" <marc.grav...@gmail.com> schrieb im Newsbeitrag
news:1180520629.679372.198320@m36g2000hse.googlegroups.com...

>> Not so; try this:

> ref ECMA 334, 3rd edtion; 14.4.2.2 Better function member

> "If one of MP and MQ is non-generic, but the other is generic, then
> the non-generic is better."

Actually, your conclusion is right. But it's the wrong rule.
A generic member is a member that has itself type parameters, not a method
that has a type parameter as a type of its parameters.

Applicable is the rule of more specific parameter types:

"Otherwise, .... if one method has more specific parameter types, then that
method is better. .....
A type parameter is less specific than a non-type parameter. ...."

Christof


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first