Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Allow implicit implementation of internal interfaces #3599

Closed
dotMorten opened this issue Jun 19, 2015 · 14 comments
Closed

Proposal: Allow implicit implementation of internal interfaces #3599

dotMorten opened this issue Jun 19, 2015 · 14 comments

Comments

@dotMorten
Copy link

When you want to implement an interface on a class, you can do it implicit or explicit. Ie

public interface IMyInterface
{
    void MyMethod();
}
public class MyClassImplicit : IMyInterface
{
    public void MyMethod() { }
}
public class MyClassExplicit : IMyInterface
{
    void IMyInterface.MyMethod() { }
}

However if I create an internal interface You are forced to implement interfaces explicitly.

internal interface IMyInterface
{
    void MyMethod();
}
public class MyClassImplicit : IMyInterface
{
    internal void MyMethod() { } //Won't compile
}
public class MyClassExplicit : IMyInterface
{
    void IMyInterface.MyMethod() { } //This works
}

Implementing implicitly has a lot of nice features - I don't have to always cast to the interface to use it. This becomes very useful for wrapping native interop classes. I can create an interface that ensures that all classes that wrap native objects follow a common pattern. For instance:

    internal interface INativeWrapper : IDisposable
    {
        internal IntPtr Pointer { get; }
    }

That way if all my classes that wrap my features from my native interop layer all expose the pointer (or similar) in a common way, and always implements IDisposable. So I can just write

IntPtr ptr = MyClass.Pointer;

However, because I'm forced to explicitly implement classes, this benefit goes away somewhat, by forcing casting on my, and it's not as discoverable from intellisense code that this is available.

IntPtr ptr = ((INativeWrapper)MyClass).Pointer;

Naturally if you implement an internal interface implicitly, you would be forced to use the 'internal' or a more accessible modifier on the members.

@clairernovotny
Copy link
Member

Here's another usage: internal-only setters for properties

internal interface IFoo 
{
 string Bar { get; set;}
}

public class Foo : IFoo
{
   public string Bar {get; internal set;}
}

That should be valid because the get has greater visibility than the interface requires.

@sharwell
Copy link
Member

📝 You are only forced to implement the interface explicitly when the signature includes internal types. Otherwise you do have the option of creating a public method that implicitly implements the interface method.

💭 I think this proposal would be more clearly worded as follows (and I would likely be in support of this):

Allow members with internal accessibility to implicitly implement members of an internal interface.

@clairernovotny
Copy link
Member

@sharwell in my example, I got errors unless I used an explicit impl. The types were not internal.

@sharwell
Copy link
Member

@onovotny The problem is your MyMethod method is marked internal. Only a member marked public is allowed to implicitly implement an interface member, regardless of the accessibility of the interface¹. The following code does compile, and MyMethod implicitly implements the internal interface method:

internal interface IMyInterface
{
    void MyMethod();
}
public class MyClassImplicit : IMyInterface
{
    public void MyMethod() { }
}

¹ I could be wrong here; I have not verified whether this restriction applies to interfaces which are nested within another type.

@clairernovotny
Copy link
Member

@sharwell In my example, I have an property with different accessibility for the setter.

The idea is that for consumers of my library, I want the object to be unchangeable. Inside my library, I want to pass the object around as an interface as I'm doing things via interface composition.

So I have an internal interface that has the get/set. I'd expect, and hence the proposal here, that a public get/internal set would be able to implement the interface.

@sharwell
Copy link
Member

@onovotny That's exactly what I said with my summarized version of your proposal. 😄

@dotMorten
Copy link
Author

Good point on the internal member types (that's actually my real scenario).
So yes none of this is strictly needed - however when working on a big project with many developers, being able to force how the internal APIs is built gets quite important. This is somewhat similar to the request of having an "internal AND protected" modifier. You could just mark it internal, but internally you can't restrict non-subclasses from calling it.

@gafter
Copy link
Member

gafter commented Mar 20, 2017

We are now taking language feature discussion on https://github.com/dotnet/csharplang for C# specific issues, https://github.com/dotnet/vblang for VB-specific features, and https://github.com/dotnet/csharplang for features that affect both languages.

See also #18002 for a general discussion of closing and/or moving language issues out of this repo.

@gafter gafter closed this as completed Mar 20, 2017
@dotMorten
Copy link
Author

@gafter So we need to move these over? Or are you closing it because you did?

@gafter
Copy link
Member

gafter commented Mar 20, 2017

I closed it because it hasn't been commented in over a year, the LDM isn't tracking it, and there is nobody on the LDM who has taken it up as a champion. Yes, if you're still interested in this, please move it over.

See also #18002 for a general discussion of closing and/or moving language issues out of this repo.

@dotMorten
Copy link
Author

Let me get this straight: If you ignore the issue long enough and no one with the power to make things happen bother making a proper informed decision, it gets closed? So we should add a useless "ping" comment every few months to "keep it alive" ? Just because it hasn't been picked up for implementation, doesn't mean it's invalid or a bad idea.
I'd prefer issues doesn't close until there's a proper technical reason why.

@gafter
Copy link
Member

gafter commented Mar 22, 2017

No, a ping will just move it later on the list of issues to be dealt with. See #18002 for a general discussion of closing and/or moving language issues out of this repo. This discussion is off topic here.

@gafter
Copy link
Member

gafter commented Mar 22, 2017

To add to that, the reason I closed this issue is that, besides the lack of community interest, my informed opinion is that this would never rise to the level needed for us to devote any effort to making it happen, and even if someone on the language design team tried to push it, there would be pushback.

However, you're welcome to open an issue on csharplang and continue discussion of the proposal. If there were enough community support it is possible (though unlikely in my opinion) that we would devote resources to this instead of the scores of (in my opinion) more valuable proposals under consideration.

@dotMorten
Copy link
Author

@gafter see you should just have said that in the first place :-). Getting your issues closed just because they have gone stale in the Roslyn team's queue, is very discouraging to the community.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants