Static interface members

Topics: C# Language Design
Apr 7, 2014 at 11:12 AM
It would be really nice to have static Interface members. This would allow to ensure that every implementation of that given Interface has These static members. At first this does not seem to make sense but in my opinion this would increase the genereal usability of generics in combination with where clauses.
The only way to achive a similar behavior right now is by using a generic base class with a static member, this member will be duplicated for every concrete implementation of that base class. I would expect the same behavior for for every implementation of such an Interface.
The use case i hope for would be something like this:
interface IProduct {}

interface IFactory
{
  static IProduct Create();
}

class Gen<T> where T : IFactory
{
 public void Do()
 {
   var product = T.Create();
 }
}
Apr 7, 2014 at 2:59 PM
Why not to use abstract base classes for default implementation? Or extension methods if base class is not desired?

If both tools are not good enough - where that static implementation would be?
Apr 7, 2014 at 3:19 PM
Why not make it an instance method then?
Apr 7, 2014 at 6:22 PM
Edited Apr 7, 2014 at 6:23 PM
The implementation would be on the type that implements the Interface:
class ProviderFactory : IFactory
{
  public static IProduct Create() { return ...; }
}

class ElementFactory : IFactory
{
  public static IProduct Create() { return ...; }
}
If i use an abstract base class there would be only one concrete implementation of that static member. But as shown in my example ProviderFactory and ElementFactory would have two complety unique implementation of that static member while still fullfilling the Interface IFactory which is egnough to satisfy my Gen<T> class from the first post.
Unfortunately i don't know the use case i had back when i had the idea for that Feature (some 2 years ago), and i used some Kind of reflection on typeof(T).GetMethod("Create").Invoke and thought this would be alot cleaner.
Apr 7, 2014 at 6:45 PM
I feel that static is not good for factories - use MEF, AutoFac, Unity, Ninject to get factory and ask it to create products.
Apr 7, 2014 at 9:05 PM
I only used "Factory" as an identifier to illustrate my example, not because i think this would be the best way to handle that specific Scenario. I could have used A, B and C as identifiers.

Please consider the Feature more in General. And if you still don't like it or think it is in General not a good idea, that is completly fine with me. I just stumpled upon this once and was wondering what if...

Now when i think about it, it really does only make sense in relation to generic constraints in every other case you would know the specific type anyway, so this should be taken into consideration.
Apr 7, 2014 at 9:38 PM
@Flowster,

As @Galich pointed, what do you expect to achieve that you can't with base class (abstract or not) or extension methods.

Since it's not about redesigning the language or designing a new one, it's important to know what are the net benefits of introducing a new feature.

If I understand you correctly, you are proposing something like an interface having a companion hidden class with some members implemented and those members will be copied to every implementing class. What are de benefits of this duplication? How would it behave on multiple interface implementation?
Apr 7, 2014 at 9:43 PM
If you consider operators as static class members, there is great value in that feature: you could force interface implementations to define certain operators, which would be really useful with generics (especially with some INumeric-like interface, with operators only, implemented by all BCL numeric types).
Apr 8, 2014 at 12:51 AM
marcinjuraszek yes i would not only suggest static methods but all members an Interface can have.

PauloMorgado Hm, the difference would be that every type that implements a Interface with a static member also to implement that member as static. No i do not think that you understand me correctly. There is no copying or anything just a promise that a type that implements an Interface also implements that static member.
To illustrate
interface IProvidesNumbers
{
  static int GetNumber(int prev);
}

class SequentialNumbers : IProvidesNumbers
{
  public static int GetNumber(int prev)
  {
    return prev+1;
  }
}

class RandomIncrementNumbers : IProvidesNumbers
{
  private static Random _rnd = new Random();
  public static int GetNumber(int prev)
  {
    return prev + _rnd.Next(10);
  }
}

class Program()
{
  static int[] CreateArray<TAlgorithm>(int countElements)
    where TAlgorithm : IProvidesNumbers
  {
    var result = new int[countElements];
    for(int i = 0; i < countElements; i++)
    {
      // THIS is the IMPORTANT line
      result[i] = TAlgorithm.GetNumber(i > 0 ? result[i] : 0);
    }
    return result;
  }

  static void Main(string[] args)
  {
    var seq = CreateArray<SequentialNumbers>(10);
    var rnd = CreateArray<RandomIncrementNumbers>(10);
  }
}
I KNOW there are otherways to achive that result, but not without creating instances of various types.


To take marcinjuraszek example, this would look like something like this: (i don't know his specifics)
interface INumeric
{
   static INumeric operator+(INumeric a, INumeric b);
}

class BigInteger : INumeric
{
  // explicit Interface implementation
  static INumeric INumeric.operator+(INumeric a, INumeric b) 
  { 
     return (BigInteger)a + (BigInteger)b; 
  }

  public static BigInteger operator+(BigInteger a, BigInteger b) { /* do stuff */ }
}

class Calculator<T> where T : INumeric
{
  public INumeric Add(INumeric a, INumeric b)
  {
    return a + b;
  }
}
Apr 8, 2014 at 12:56 AM
I think I got it now.

At this moment, for all intents and purposes, interfaces only define contracts for the objects. You propose the same for classes (members of the class, thus, static).
Apr 8, 2014 at 9:57 PM
You can already implement this functionality by using normal interfaces. For example:
interface IProductFactory
{
    IProduct Create();
}

class Gen(private IProductFactory factory)
{
    public void Do()
    {
        var product = factory.Create();
        // ...
    }
}
The only objection I can think of is that you have to create this IProductFactory object somewhere instead of being able to pass a type. However, I don’t see this as problematic. Compare new Gen<MyProductFactory>() and new Gen(new MyProductFactory()) — not that much difference in typing. And if you want the implementation of MyProductFactory to be private to Product, you can do that and expose it through a static property — thus, you get new Gen(Product.Factory).
Apr 8, 2014 at 10:19 PM
I am in favor of this feature, particularly if operators can be supported. However, this is very unlikely to be merely a language feature, this would need to be something built into the CLR itself.
Apr 9, 2014 at 12:41 PM
Static interface members are an interesting feature because they could be part of a solution to the problem of having better "where T : new(...)" constraints on generic types, by using static members instead of constructors.
Apr 9, 2014 at 12:56 PM
Edited Apr 9, 2014 at 12:56 PM
Flowster wrote:
It would be really nice to have static Interface members. This would allow to ensure that every implementation of that given Interface has These static members.
Well, how would you expect this code to behave:
interface I
{
    static void Print();
}

class A : I
{
    public static void Print() { Console.WriteLine("A.print"); }
}

class B : A, I
{
    public static void Print() { Console.WriteLine("B.print"); }
}

I i = new B();
i.Print();
A a = new B();
a.Print();
Apr 9, 2014 at 1:29 PM
You can't invoke static methods on the instance. The code you show is not valid C# code regardless of static interfaces.

At most, this would be possible:
interface I
{
    static void Print();
}

class A : I
{
    public static void Print() { Console.WriteLine("A.print"); }
}

class B<T>
    where T:I
{
    public static void Print() {T.Print(); }
}
Apr 9, 2014 at 1:46 PM
I still don't see why you need to use static methods on a generic type. Just use instance methods. I think the use of static methods shouldn't be promoted anyway and if we really need to pass a different static method to the generic type just make it accept a delegate and pass the static method there.
Apr 9, 2014 at 1:47 PM
Edited Apr 9, 2014 at 1:49 PM
Same way it does now:

For line: i.Print();
Member 'I.Print()' cannot be accessed with an instance reference; qualify it with a type name instead
For line: a.Print();
Member 'A.Print()' cannot be accessed with an instance reference; qualify it with a type name instead
And and if accessed from the Interface reference directly, this would be a viable solution
For line: I.Print();
Member 'I.Print()' cannot be accessed with an Interface reference; qualify it with a type argument instead
Apr 9, 2014 at 1:58 PM
Edited Apr 9, 2014 at 2:00 PM
@PauloMorgado: I see your point, you propose not to introduce a possibility to call the static method from interface-typed instance.

But then, is there any use of the proposed feature outside of generic constraints? Would it not be better just to generalize generic constraints instead?
Apr 9, 2014 at 2:12 PM
Edited Apr 9, 2014 at 2:25 PM
Stilgar wrote
I still don't see why you need to use static methods on a generic type. Just use instance methods. I think the use of static methods shouldn't be promoted anyway and if we really need to pass a different static method to the generic type just make it accept a delegate and pass the static method there.
Yes you can do it differently but that is the case for almost every Feature request right now, even if you go back, why introduce Properties as a first class citizen, when you can have the same functionality by using Getter and Setter methods.

I think what you gain by this is an additional construct you can use to be declaritive about your types, you can enforce certain constructs at compile time or even before that, depending on your codings Tools that could tell you: "you have to implement that function".
Also when you write a generic type or methods you can be more verbose about what you expect from a certain type Argument. So i think this would be a gain for C# to improve in the direction of declaritive programming.

The language changes to allow this are minimal, no new keywords, no new Operators. But and that is the problem, the CLR cannot refere to Members based on the type that is given as Type Argument, hence the call TAlgorithm.GetNumber(i > 0 ? result[i] : 0); from my earlier example must be rewritten into typeof(TAlgorithm).GetMethod("GetNumber", new [] { typeof(int) }).Invoke(null, i > 0 ? result[i] : 0) which would be supposedly slower as with native Support.
Apr 9, 2014 at 2:20 PM
Edited Apr 9, 2014 at 2:21 PM
VladD wrote:
But then, is there any use of the proposed feature outside of generic constraints? Would it not be better just to generalize generic constraints instead?
I think you have a Point there, generalizing the constraint System might well be the better solution.
void Do<T>()
where T : has(static void Print())
{
  T.Print();
}
I would totally love that!
Apr 9, 2014 at 2:24 PM
Flowster wrote:
I think you have a Point there, generalizing the constraint System might well be the better solution.
void Do<T>()
where T : has(static void Print())
{
  T.Print();
}
I would totally love that!
But if i think about that, that seem a bit too dynamic for me, what do you think?
Apr 9, 2014 at 2:38 PM
Edited Apr 9, 2014 at 2:38 PM
Flowster wrote:
But if i think about that, that seem a bit too dynamic for me, what do you think?
Well, generalization of generic constraints is a long-standing topic. For example, many people would like to be able to express existence of static operator + (T, T) etc. and use it in generic code (which is not possible without expensive dynamic or both expensive and hard to maintain reflection).

I actually don't think the static method constraint is too dynamic. I'd love to see it in the language, too. However I am not sure whether it can be done in an efficient way from the code generation point of view. It would be nice to hear from a specialist whether generic constraint improvement would require changes on IL level, and how complicated these changes would be.
Apr 9, 2014 at 3:44 PM
VladD wrote:
Well, generalization of generic constraints is a long-standing topic. For example, many people would like to be able to express existence of static operator + (T, T) etc. and use it in generic code (which is not possible without expensive dynamic or both expensive and hard to maintain reflection).
Actually this is possible without using dynamic/reflection. Though it does require quite a bit of boilerplate code and one additional generic argument to get it to work.
I actually don't think the static method constraint is too dynamic.
It's way more dynamic than you think. OK, you have a T and you require that it has one static method with a certain name and signature, that works fine. But when you need to actually call the method you have a problem: you don't know the method when you emit the IL, there's no metadata token that you can put in the IL stream to indicate what method should be called. T can be a thousand things, a string or an int or a type that the compiler has not even seen when it compiled the generic type/method.

So, can this thing made to work? Yes, the compiler emits code that at runtime identifies the actual type of T and find and calls the static method by using reflection. And that's pretty much the same thing you get when you use dynamic.
Apr 9, 2014 at 3:55 PM
Edited Apr 9, 2014 at 3:55 PM
mdanes wrote:
It's way more dynamic than you think. OK, you have a T and you require that it has one static method with a certain name and signature, that works fine. But when you need to actually call the method you have a problem: you don't know the method when you emit the IL, there's no metadata token that you can put in the IL stream to indicate what method should be called. T can be a thousand things, a string or an int or a type that the compiler has not even seen when it compiled the generic type/method.

So, can this thing made to work? Yes, the compiler emits code that at runtime identifies the actual type of T and find and calls the static method by using reflection. And that's pretty much the same thing you get when you use dynamic.
Just tobe clear you are refering to this:
void Do<T>()
where T : has(static void Print())
{
T.Print();
}
?
Apr 9, 2014 at 4:08 PM
Flowster wrote:
Just tobe clear you are refering to this:
Yup. T is known only at runtime. Do<Foo>() and Do<Bar>() share the same code and that code has to figure out what function to call depending on the type, there's no mechanism to do this except reflection. There's an exception if T is a value type: Do<int> and Do<float> do not share the code and the JIT compiler could statically determine which static function to call.
Apr 9, 2014 at 6:00 PM
VladD wrote:
@PauloMorgado: I see your point, you propose not to introduce a possibility to call the static method from interface-typed instance.

But then, is there any use of the proposed feature outside of generic constraints? Would it not be better just to generalize generic constraints instead?
The obvious one is constraints and use of operators.

But I don't know if that is even feasable.
Apr 9, 2014 at 6:14 PM
@PauloMorgado: using operators is again covered with generic constraints (in a on-generic scenario one can use them out of the box).

@mdanes: well, so your point is that this needs changes on code emitter side. Good so far, but two follow-up questions:
  • How complicated should be the changes to make the call efficient?
  • Can one achieve better codegen/performance/whatever implementing only static interface members, as it was originally proposed?
Apr 9, 2014 at 7:24 PM
  • How complicated should be the changes to make the call efficient?
  • Can one achieve better codegen/performance/whatever implementing only static interface members, as it was originally proposed?
Static interface members (as described in the initial proposal) and constraints such as "has(static void Print())" are really the same thing. Both are supposed to tell the compiler that a static method with a certain signature exists but they can't tell exactly which method. All you have is a method name and you can't put that in the IL stream.

The reason why interface constraints work is that the interface has a definition of the method and as a result there's a method token you can put in IL to call the interface method. From here the CLR takes over and uses the standard virtual call mechanism to figure out what method to call.

As for what needs to change to make the call efficient, well, if reflection/dynamic is not efficient enough then the only thing you can do is to change the CLR. There are several ways to do it but none of them are trivial. You'll probably need to change the metadata format or add a new IL instruction to get this to work reasonably fast. An interesting thing is that a CLR based implementation would very likely exclude any sort of "has(static void Print())", if you want to do this in CLR then you have to use the interface approach.
Apr 10, 2014 at 11:22 PM
Edited Apr 10, 2014 at 11:26 PM
eldritchconundrum wrote:
Static interface members are an interesting feature because they could be part of a solution to the problem of having better "where T : new(...)" constraints on generic types, by using static members instead of constructors.
That's a good point. I think this is actually a better way to handle the where T : new(...) case. It seems more flexible and allows for prettier solutions to some situations (like when one implementation of a class can create an instance of itself based on input, but doing so requires a long-running task or has side effects).

I definitely like the idea of static interface members or generic constraints based on the presence of static members. An example that came to mind when I first started reading this thread was Parse. There are sometimes instances where you want to have a generically typed class, where the generic can always be parsed from a string. A classic case for this might be something like this, T GetFromQueryString<T>(string url, string parameterName) where T : IParsable<T>. IParsable<T> could have one member, static T Parse(string value);, and you could easily implement a generic query string parser without much effort.

Something else that I've wanted in the past that isn't really the same thing but is related: it would sometimes be nice if we could have a static class that implements an interface, public static class Foo : IBar. Really, this is just a quicker way of implementing a singleton design pattern.
Feb 19, 2015 at 10:40 PM
I know this is an old topic, but I find myself really wishing for this in a base class for components that, by the pattern, are supposed to have a static member. It would be especially great if I could access it from the base class via generics, but even just being able to require implementations to have the method would be real nice as right now there's no compile-time way to ensure the pattern is correctly followed. Has this been further explored?
Developer
Feb 25, 2015 at 5:20 AM
The Roslyn team no longer uses this site. Your comments are most welcome over at https://github.com/dotnet/roslyn