views:

3083

answers:

12

What is the argument against declaring protected-access members on interfaces? This, for example, is invalid:

public interface IOrange
{
    public OrangePeel Peel { get; }
    protected OrangePips Seeds { get; }
}

In this example, the interface IOrange would guarantee that implementors at least provide an OrangePips instance to their inheritors. If the implementor wanted to, they could expand the scope to full public:

public class NavelOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    protected OrangePips Seeds { get { return null; } }
}

public class ValenciaOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    public OrangePips Seeds { get { return new OrangePips(6); } }
}

The intent of protected members on interfaces is to provide a support contract for inheritors (sub-classes), for example:

public class SpecialNavelOrange : NavelOrange
{
    ...
    // Having a seed value is useful to me.
    OrangePips seeds = this.Seeds; 
    ...
}

(Admittedly, this wouldn't work for structs)

I can't see much of a case for private or internal modifiers in interfaces, but supporting both public and protected modifiers seems perfectly reasonable.


I'm going to try explaining the utility of protected members on interfaces by separating them from interfaces entirely:

Let's imagine a new C# keyword, support, to enforce inheritor contracts, so that we declare things as follows:

public support IOrangeSupport
{
    OrangePips Seeds { get; }
}

This would allows us to contract classes to provide protected members to their inheritors:

public class NavelOrange : IOrange, IOrangeSupport
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    protected OrangePips Seeds { get { return null; } }
}

This is not particularly useful, because classes would already imply this contract by providing the protected members in the first place.

But then we could also do this:

public interface IOrange : IOrangeSupport
{
   ...
}

Thereby applying IOrangeSupport to all classes which implement IOrange and requiring them to provide particular protected members - which is not something we can currently do.

A: 

An interface is all about what a certain object can do, so when using a class which implements that interface the developer will expect all the members to be implemented, so the protected access modifier won't mean anything for interfaces.

Gerrie Schenck
Agreed, but I'm not so much asking why implementing members of an interface can't be optional (as they should not), but why I can't specify their level of access.
A J Lane
+5  A: 

Interface members are a public API; things like protected etc are implementation details - and interfaces don't have any implementation. I suspect what you are looking for is explicit interface implementation:

public class NavelOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    OrangePips IOrange.Seeds { get { return null; } }
}
Marc Gravell
Explicit interface implementations are still `public`, so it's not really what I'm looking for. Specifically, I'm thinking `protected` members would provide an API between sets of base classes and their inheritors.
A J Lane
That is strictly between the base-class and the inheritor - it simply has nothing what-so-ever to do with the interface. If you want a protected method in the base-class, simply declare one.
Marc Gravell
Right, but suppose we have a broad range of base-classes implementing the interface. It seems reasonable to define a contract which says that anyone deriving from those classes can expect a certain standard of support.
A J Lane
A: 

An Interface contains only public members. Protected means whatever you're declaring is only available to the class and derived class instances.

Jason Punyon
"methods" should read "members" - can also be properties and events
Marc Gravell
@Marc Gravell: Thanks...I'm typing a little too quickly this morning...
Jason Punyon
+4  A: 

Interfaces exist to allow people to access your class without knowing what the concrete implementation is. It completely divorices the implementation from the data passing contract.

Therefore, everything in an interface must be public. Non-public members are only useful if you have access to the implementation and therefore don't meaningfully contribute to an interface definition.

JaredPar
+12  A: 

Because it makes no sense. An interface is a publicly exposed contract. I am an IThing, therefore I will perform IThing methods if asked. You can't ask an IThing to confirm it performs methods it can't tell you about.

annakata
But an IThing can tell its inheritors about non-`public` methods. Why can I not ask it to perform additional IThing methods in that context?
A J Lane
Because those aren't IThing methods, those are the base class's methods/properties. What if two IThing implementations implement this protected member and a third one doesn't because it just doesn't make sense. What then?
siz
@AJ - Confused. An IThing cannot tell it's inheritors about non-publics, that's the point right?
annakata
@siz: The third one must implement it: it's in the interface.
A J Lane
@annakata: Suppose AbstractThing implements IThing and ConcreteThing derives from AbstractThing. AbstractThing can tell ConcreteThing about protected (non-public) members. The idea is that IThing could also specify some of those
A J Lane
@AJ - but again that's an implementation specific detail and you can already force concrete to implement with abstract. Interfaces and Abstracts do *some* of the same things for very different reasons.
annakata
Yes, but only if abstracts make sense (or are possible) for the given classes.
A J Lane
A: 

FWIW, you can't even declare members "public" on an interface in C#.

Dave Markle
+13  A: 
Anton Gogolev
Best darned explanation I have every heard of an interface. +1
WolfmanDragon
A: 

There's sound judgment in current design of interfaces which is that it offers implementers greater flexibility. Remember that very often interfaces are written by framework programmers and implementers are different folks. To enforce implementation would be needlessly harsh.

Frederick
A: 

An interface is a contract that promises certain functionality to clients. In other words, the purpose of an interface is to be able to cast a type into it and pass it around like that to code that needs the features guaranteed by that interface. Since client code of a type cannot access protected members of that type, it makes no sense to declare protected items in an interface.

Vojislav Stojkovic
A: 

By implementing an interface the type states that it supports a specific set of methods. If any of these methods were not public, it would not be available to callers and thus the type would not support the interface as stated.

Brian Rasmussen
+7  A: 

I think everyone hammered the point of an interface having only public members, no implementation details. What you are looking for is an abstract class.

public interface IOrange
{
    OrangePeel Peel { get; }
}

public abstract class OrangeBase : IOrange
{
    protected OrangeBase() {}
    protected abstract OrangePips Seeds { get; }
    public abstract OrangePeel Peel { get; }
}

public class NavelOrange : OrangeBase
{
    public override OrangePeel Peel { get { return new OrangePeel(); } }
    protected override OrangePips Seeds { get { return null; } }
}

public class ValenciaOrange : OrangeBase
{
    public override OrangePeel Peel { get { return new OrangePeel(); } }
    protected override OrangePips Seeds { get { return new OrangePips(6); } }
}

Edit: It is fair to argue that if we have a PlasticOrange that derives from a class Ornament, it can only implement IOrange and not the Seeds protected method. That is fine. An interface by definition is a contract between a caller and an object, not between a class and its subclasses. The abstract class is as close as we come to this concept. And that is fine. What you are essentially proposing is another construct in the language through which we can switch subclasses from one base class to another without breaking the build. To me, this doesn't make sense.

If you are creating a subclass of a class, the subclass is a specialization of the base class. It should be fully aware of any protected members of the base class. But if you suddenly want to switch the base class out, it makes no sense that the subclass should work with any other IOrange.

I suppose you have a fair question, but it seems like a corner case and I don't see any benefit from it to be honest.

siz
An abstract class only works if it is reasonable to set the base -classes of `NavelOrange` and `ValenciaOrange` to the same thing. Suppose a class `PlasticOrange` which already derives from `Ornament`.
A J Lane
Then I'd doubt the orange has Seeds or can Peel. On a serious note, this is a fair point but we are constrained by the OOP single-inheritance model so I have no good answer. That being said, this solution solves the original case, unless you plan on creating the model you're hinting at. :)
siz
A: 

This is a sample code where abstract classes can't be used to force some inherithed classes to have some protected members:

public interface IUseful<T>
{
    void foo(T arg);
    // protected void foo1(T arg);
    // Can't do it
}

public abstract class AbstractC
{
    // protected void foo1(??????? arg)
    // Can't do it to force C1 and C2 to have foo1 parametrized on
    // their innerr classes
}

public abstract class AbstractC1 : AbstractC
{
    public class InnerC1 { }
}

public abstract class AbstractC2 : AbstractC
{
    public class InnerC2 { }
}

public class C1 : AbstractC1, IUseful<AbstractC1.InnerC1>
{
    public void foo(InnerC1 arg) { }
    protected void foo1(InnerC1 arg) { } // No way to force foo1 to be protected
                                         // on both C1 and C2
}

public class C2 : AbstractC2, IUseful<AbstractC2.InnerC2>
{
    public void foo(InnerC2 arg) { }
    protected void foo1(InnerC2 arg) { } // No way to force foo1 to be protected
                                         // on both C1 and C2
}

Ok, the cleaner solution here is multiple inheritance and not protected members in intherface. But, without mixins, without multiple inheritance, it's often frustrating to design cool data structures in java/C#

ceztko