optional keyword for members in Interfaces

Topics: C# Language Design
Sep 3, 2014 at 7:48 PM
Okay, so first things first. English isn't my main language so i'm really sorry if i make some mistakes, and i am new to programming so i'm really sorry if something that i'm proposing here actually exists...

Currently, when we create an interface we need to implement every single thing from it in our classes. Which works fine if you don't have any more complex and abstract design. So basically, what if i want to have class which describes different types of companies and i want them, to on a top level be exactly the same. Now, i would need to create something like this:
public interface ICompany
{
    String Name { get; set; }
    String Address   { get; set; }
    Int32  StateRegistrationNumber { get; set; }
    ...
    ...
}

public class Company : ICompany
{
    (here we implement everything from the interface)
}
But what if we have different types, sizes, etc... of companies, that have different info describing them?
One of the solution would be to create more interfaces that are implementing the main one, something like this:
public interface IAgricultureCompany : ICompany
{
   IList<String> Crops;
   String AgriculturalType { get; set; }
}

public class AgricultureCompany : IAgricultureCompany
{
   (here we implement everything from the interface)
}
Or we ditch that and just stick to ICompany, but we implement company specific info manually in the classes themselves.
All of that require alot of repetetive and time consuming job.

Wouldn't it be better to have something like an 'optional' keyword for interface members, so we can choose what we want to implement. This way we can only stick to one interface, no more code repetition, no more complicating and confusing multiple interfaces. Example:
public interface ICompany
{
    String Name { get; set; }
    String Address   { get; set; }
    Int32  StateRegistrationNumber { get; set; }
    optional IList<String> Crops;
    optional String AgriculturalType { get; set; }
    optional ...
    optional ...
    ...
    ...
}
The example with companies maybe isn't the best one, but i think you can see now why it would be useful to have something like this.
Sep 3, 2014 at 8:03 PM
Sounds like a very bad idea to me. How would you know if a member is implemented or not?
Also you don't need to use derivation, you can just implement multiple Interfaces.
I don't see where this would cause much repetetive work.
Sep 3, 2014 at 8:10 PM
Edited Sep 3, 2014 at 8:11 PM
That would completely break the Liskov Substitution Principle, making interfaces essentially useless.

So the sub-interfaces solution that you proposed probably is the way to go here. Alternatively, use abstract classes where you can provide a (meaningful!) default implementation.
Sep 3, 2014 at 10:13 PM
An interface is a contract. I would like payments to be optional in the contract I made with the bank to buy my house, but they say I have to fulfill every clause in the contract.
Sep 5, 2014 at 12:08 AM
What is necessary is a means for interfaces to specify default implementations for methods. Interface versioning could be ENORMOUSLY improved if the class loader could, in cases where a class claims to implement an interface but doesn't include all the members, check the interface for a list of "default implementation" static classes and generate a default implementation that would call a static method of the first class which contained a suitable one. For example, if IEnumerable<T> inherited from class IEnumerableGenericMarker which did nothing but inherit from IEnumerable, then the latter could mention
public static class NonGenericIEnumerableClassHelper<T> where T:class,IEnumerableGenericMarker
{
  static Func<T, IEnumerator> enumeratorMethod = lookupEnumeratorMethod;
  public static GetEnumerator(T it) { return enumeratorMethod(it); } 
  static IEnumerator lookupEnumeratorMethod(T it)
  {
    ... reflection to find an `IEnumerable<U>.GetEnumerator()` implementation ...
    ...    for some type U, and store it in `enumeratorMethod`
    return enumeratorMethod();
  }
}
along with a similar class which includes a struct constraint and defines GetEnumerator to take a ref T parameter. Bingo--one method eliminated from 99.9% of non-iterator IEnumerable<T> implementations. Imagine all the man hours that could have been saved if that was added five years ago.

Further, imagine how useful it would be to extend IEnumerator<T> a little bit with a method like
int Move(int);
whose default implementation would be:
public static class NonGenericIEnumerableClassHelper<T,U> where T:class,IEnumerator<U>
{
  static int Move(T it, int count)
  {
    while(count > 0 && it.MoveNext())
      count--;
    return count;
  }
}
If such a method existed and types like List<T> implemented it efficiently, then accessing the 1,500,000th item of an IEnumerable<T> formed by concatenating two million-item lists would be efficient, since it could skip through all 1,000,000 items of the first list in one operation, and 500,000 items of the second list in a second operation, rather than having to slog through 1,500,000 individual items. A pretty major win, IMHO.
Sep 5, 2014 at 4:14 PM
I agree with the others, to add something like "optional" members to an interface would largely defeat their purpose as being a code contract. What would happen if you downcast a concrete TelecommunicationsCompany to an ICompany and attempted to reference the Crops property? Why should the concept of Crops be something that all companies inherit? As you work with additional company types would you extend out the base ICompany interface in order to accommodate all potential members? The use of discriminator interfaces is much more appropriate.

However, you are free to do something like make those members all nullable and have an abstract base class which handled the default implementation to return a null value. That would effectively accomplish the same thing, but I still argue that it is not good design.
Sep 5, 2014 at 9:08 PM
Halo_Four wrote:
I agree with the others, to add something like "optional" members to an interface would largely defeat their purpose as being a code contract. What would happen if you downcast a concrete TelecommunicationsCompany to an ICompany and attempted to reference the Crops property? Why should the concept of Crops be something that all companies inherit? As you work with additional company types would you extend out the base ICompany interface in order to accommodate all potential members? The use of discriminator interfaces is much more appropriate.
Every interface method must have an implementation somewhere, but if many implementing classes can be expected to implement a particular member the same way, having a single default implementation which invokes a static method (which receives a parameter of the appropriate type) may be better than requiring every implementer of the interface to manually chain to a static method.

It should also be noted, btw, that if an interface includes a method Foo and a property CanFoo, an implementation whose Foo method throws NotSupportedException would only violate the LSP if its CanFoo property returned true. In the absence of a default-implementation mechanism, "kitchen-sink" interfaces like IList<T> make things painful for implementers that don't expect consumers to care about many methods (IList<T> also happens to be very bad at identifying which methods will actually be usable in many situations), but they have some major advantages in some situations.

Imagine, for example, that IList<T> were subdivided into IReadableByIndex<out T>, IWritableByIndex<in T>, IPermutable, ICountable, IInsertableByIndex<in T>, IDeletableByIndex, IAppendable<in T>, etc. How many different composite interfaces would one need in order to ensure that any user of a collection which implements various abilities would be able to hold a single reference of a type that can accommodate all those abilities, but collection classes wouldn't have to implement any methods they couldn't support? Splitting IList<T> into covariant, contravariant, invariant, and type-agnostic portions, and possibly also defining IImmutableList<out T> would be helpful, especially since the convariant and contravariant portions could inherit the type-agnostic portion, the immutable portion could inherit the covariant portion, and the invariant portion could inherit the covariant and contravariant portions, but attempting precision beyond that would be less than helpful.

Now consider how one would design a family of collection-wrapper classes which should encapsulate a collection and implement all its methods by writing to a log and then chaining to the encapsulated collection. If IList<T> is split into the five related parts discussed above, then five wrapper classes would suffice (one for each part), and the wrapper classes could have many of the same relations among themselves as the interfaces in question [the invariant wrapper could only inherit from the covariant wrapper]. Not wonderful, but not horrible either. Splitting it into the seven earlier-described independent parts, however, and then defining composite interfaces for every possible meaningful combination, however, would require the creation of a separate wrapper class for every possible combination of interfaces, and most of the chaining methods would need to be duplicated in many wrapper classes. Nasty.

There are times when it's useful to be able to receive a variable of an interface type and know that it will in fact implement all the methods indicated thereby, but that doesn't mean one can't have a base-level kitchen-sink interface which promises that all methods will "exist" but not that they'll all "work", and then have other interfaces which inherit from and don't define new members but add additional contractual requirements for implementers. If code will need to receive reference to an object which may or may not provide a feature, and pass it to a consumer which may or may not need that feature, life will be easiest for the code in the middle if it can accept an object that "might" provide the feature and pass it to a consumer that "might" need it, without having to worry about who has or needs the feature in question.
Sep 6, 2014 at 3:53 PM
I don't disgree. There are times when a common interface describes enough cross-cutting concerns that it makes sense to have the interface describe the more common members and allow the implementers to opt-into the different functionality. IList<T> is a good example of that. Stream could be another, although I might argue that it might've been more appropriate to have separate interfaces describing readable streams and writable streams like Java does. There are even places in the framework where the capabilities are not appropriately interrogated and assumptions are made as to which members are properly implemented, such as ASP.NET with non-seekable streams used in VirtualFileProviders. It's a question of threshold and whether the members make sense.

My argument against the original poster was directed primarily at his specific use-case of trying to define a kitchen-sink interface to describe all potential important members of companies in different industries. If his application was intended to deal primarily in agriculture then it might make sense, but if it's more general purpose then you end up walking down a path where you're ultimately building out this infinitely large interface which could encapsulate all of the important data points of all possible markets, which just doesn't make a lot of sense.

As for your other suggestions, I had a couple of questions. One, at least from a syntactical point of view, why wouldn't default interface implementations be defined inline with the interface? Is this not something decided upon by the interface itself in some way, or are you thinking of some kind of alternate resolution which might occur at compile-time or runtime? Also, how would you deal with the diamond inheritance scenario of a class implementing two different and unrelated interfaces which each define a method with identical signatures and optional implementations? Java 8, which has default interface implementations, simply doesn't allow a class to extend from multiple interfaces in such a fashion at all, but C# does either implicitly or through explicit implementation, so that is a problem that would have to be resolved.

We've discussed your use case for something like this before. I am still of the opinion that your specific problem could be solved without changing the language or the semantics of the runtime by making the internal LINQ operators a little more intelligent than they are today in regards to the types of enumerables that they working with. Even with the language features you propose those methods would require those modifications as they almost always return a new type as the enumerator which hides the capabilities of the underlying types. Your scenario makes sense and would benefit tremendously from LINQ being able to exploit that information but it's also quite specific and combined with any other countless specific scenarios could force the amount of code necessary to handle the common and specific cases to explode exponentially.
Sep 8, 2014 at 9:46 PM
Halo_Four wrote:
My argument against the original poster was directed primarily at his specific use-case of trying to define a kitchen-sink interface to describe all potential important members of companies in different industries. If his application was intended to deal primarily in agriculture then it might make sense, but if it's more general purpose then you end up walking down a path where you're ultimately building out this infinitely large interface which could encapsulate all of the important data points of all possible markets, which just doesn't make a lot of sense.
I agree that the original use case was a poor one, but that doesn't mean that default interface implementations wouldn't have some excellent use cases.
As for your other suggestions, I had a couple of questions. One, at least from a syntactical point of view, why wouldn't default interface implementations be defined inline with the interface? Is this not something decided upon by the interface itself in some way, or are you thinking of some kind of alternate resolution which might occur at compile-time or runtime? Also, how would you deal with the diamond inheritance scenario of a class implementing two different and unrelated interfaces which each define a method with identical signatures and optional implementations? Java 8, which has default interface implementations, simply doesn't allow a class to extend from multiple interfaces in such a fashion at all, but C# does either implicitly or through explicit implementation, so that is a problem that would have to be resolved.
My proposed implementation would be to tag interfaces with attributes. Although from a syntactical perspective it would be nice to allow the default implementations to be supplied within the body of the interface, requiring that the implementation of an interface be handled by classes nested within the interface definition would make it impossible to define an interface with default member implementations in any language which doesn't understand the concept. If attributes allow other classes within the same assembly to be designated as the location of default implementations, then it would be possible (perhaps awkward) to specify default interface implementations in any language which provides a syntax for defining attributes.

As for the diamond scenario, that can only occur if members can be overridden in the middle of an inheritance hierarchy. If IEnumerator<T> could define a default implementation of the non-generic IEnumerator.GetEnumerator(), that could create deadly diamonds, but if the only interface that can designate a default implementation for IEnumerator.GetEnumerator() is IEnumerator itself, then there can be no conflicting default implementations. If a class which implements IEnumerator<T> implements IEnumerator.GetEnumerator(), its implementation will be used; otherwise classes designated by IEnumerator will be searched until one is found with a suitable GetEnumerator method. This design does mean that dispatch from a generic IEnumerable.GetEnumerator() to an IEnumerable<T>.GetEnumerator() method requires Reflection, but since it would only be necessary to use Reflection once per type that shouldn't be a problem.

Note that Java's default-interface-implementation semantics do have a diamond problem precisely because Java does allow mid-level interfaces to supply default behaviors for base-level classes, and Java has a more general problem with interfaces because it cannot distinguish ((Interface1).method from ((Interface2).method, but C# has no such limitation.
We've discussed your use case for something like this before. I am still of the opinion that your specific problem could be solved without changing the language or the semantics of the runtime by making the internal LINQ operators a little more intelligent than they are today in regards to the types of enumerables that they working with.
The only way that IEnumerable<T>.Concat could manage to return an object that was powerful enough to support even Count efficiently would be to have it test all passed-in objects for implementations of ICollection<T>, IReadOnlyCollection<T>, or ICollection and then choose a wrapper class based upon the result of such testing. That might not be too horrible if Count was the only method one wanted to optimize, but there are many more beyond that which could use help.
Even with the language features you propose those methods would require those modifications as they almost always return a new type as the enumerator which hides the capabilities of the underlying types. Your scenario makes sense and would benefit tremendously from LINQ being able to exploit that information but it's also quite specific and combined with any other countless specific scenarios could force the amount of code necessary to handle the common and specific cases to explode exponentially.
The purpose of my proposal would be to avoid the exponential explosion of cases, since something like IEnumerable<T>.Concat would only need to return one type: an interface which includes many abilities which may or may not be supported, and it wouldn't have to worry about which interfaces are supported by the aggregated collections unless or until client code asked about them.

Existing code which wraps collections would need to be upgraded in order for many new collection-related features to become available to clients, though adding some methods to IEnumerator<T> rather than just IEnumerable<T> would meant that collection wrappers whose GetEnumerator() methods return an enumerator from the underlying collection could support many more efficient operations without having to be modified at all.

The biggest benefit I see with allowing default interface implementations is that it would pave the way for much smoother interface versioning. At present, if it becomes apparent that an interface should have included a member but it doesn't, there's no way to add it without breaking all existing implementations even if one could define behavior which would be reasonable for all existing implementations (e.g. add a CanWizzle property to the ThingAbilities base class and have its default implementation return false, and have the default IThing.Wizzle implementation throw NotSupportedException). Being able to have the designer of an interface add additional members would work much more fluently than defining a new interface and requiring consumers to constantly check whether they're working with the old or new interface.