16

C# provides following signature characteristics to be used while function overloading.

We know that for overloading takes into consideration only arguments; their number and types, but the objective of polymorphism is to provide same name but different usage depending upon calling strategy.

If I have a class containing two methods with the same name and signature, while one is static and another is not, C# compiler throws an error; "Class already defines a member called 'foo' with the same parameter types".​The call to both the methods are going to be different; one with the object name and the static one with a class name. Hence there is no ambiguity with calling strategy. Then why does it throw an error?

 class Example {

    public void foo() { }
    public static void foo() { }

}

class Program
{
    static void Main(string[] args)
    {

        Example e = new Example();
        e.foo(); 

    }
}
abdul
  • 1,531
  • 1
  • 14
  • 29
Yogesh lele
  • 392
  • 4
  • 17

6 Answers6

13

Reason why it is throwing an error is that static methods can be called from non-static methods without specifying type name. In this case, compiler won't be able to determine, which method is being called.

public class Foo()
{
   public static void MyMethod() {};
   public void MyMethod() {}

   public void SomeOtherMethod()
   {
      MyMethod(); // which method we're calling static or non-static ?
   }
}

EDIT

Just found this SO post regarding your case. You might want to check it also.

Community
  • 1
  • 1
Michael
  • 2,961
  • 2
  • 28
  • 54
  • 8
    But you can declare a local variable with the same name as an existing field. And you can excplicitly refer to that field using `this`. Here would be the same - this.MyMethod - instance; MyMethod or Foo.MyMethod - static. – Viktor Arsanov Sep 10 '14 at 07:20
  • @ViktorArsanov it's not about what you can or can't do here, it's all about how compiler would interperet this piece of code. It is legal to write this c# code, yet there is no way for compiler to understand which method should be called. – Michael Sep 10 '14 at 07:32
  • 1
    This answer is incorrect. Imagine if the compiler dictated for the language design team what is or isn’t legal, rather than the other way around. Since a solution (like the one Viktor suggested) is possible, *and as Viktor mentioned has already been accepted by the language in a different place*, the only question that remains now is why did the language design team not allow static/non-static members to have the same signiture/name? See my answer for the correct information. – Rashad Saleh Sep 01 '19 at 12:27
5

This error occurs because this is how the behavior is defined in the C# Language Specification. Any "ambiguous" usage (or ways to disambiguate such) is irrelevant, although such reasoning and edge-cases may have led the designers to not explicitly allow such a differentiation .. or it might simply be a C# codification of an underlying .NET CLI/CLR restriction1.

From "3.6 Signatures and overloading" in the C# specification (and in agreement with the linked documentation), formatted as bullets:

The signature of a method consists of

  • the name of the method,
  • the number of type parameters, and
  • the type and kind (value, reference, or output) of each of its formal parameters ..

Method modifiers, including static, are not considered as part of the method signature here.

And, from "1.6.6 Methods" we have the restriction and an agreeing summary:

The signature of a method must be unique in the class in which the method is declared. The signature of a method consists of the name of the method, the number of type parameters and {the number, modifiers, and types of} its parameters..

This restriction applies before (and independently of) the method being considered for polymorphism.

Also, as a closing note: instance methods must be virtual or accessed through an interface to be run-time polymorphic in C#. (Both method hiding and method overloading are arguably a form of compile-time polymorphism, but that's another topic..)


1There is support for this simply being the result of a restriction of the .NET CLI/CLR itself that is not worth bypassing (ie. for interoperability reasons). From "I.8.6.1.5 Method signatures" in ECMA-335:

A method signature is composed of

  • a calling convention [CLS Rule 15: "the only calling convention supported by the CLS is the standard managed calling convention"],
  • the number of generic parameters, if the method is generic,
  • [omitted rule]
  • a list of zero or more parameter signatures—one for each parameter of the method— and,
  • a type signature for the result value, if one is produced.

Method signatures are declared by method definitions. Only one constraint can be added to a method signature in addition to those of parameter signatures [CLS Rule 15: "The vararg constraint is not part of the CLS"]:

  • The vararg constraint can be included to indicate that all arguments past this point are optional. When it appears, the calling convention shall be one that supports variable argument lists.

The intersection between the C#/CLS and ECMA signature components is thus the method name, "the number of generic parameters", and "a list of zero or more parameter signatures".

user2864740
  • 60,010
  • 15
  • 145
  • 220
3

I feel your question is "why did the standard choose to forbid declaring two methods that differ only by the static keyword?", and therefore the answer "because the standard says so" does not look appropriate to me.

Now, the problem is, there could be any reason. The standard is the Law, and it can be arbitrary. Without the help of somebody who participated to the language's design, all we can do is speculate about the reasons, trying to uncover the spirit of the Laws.

Here is my guess. I see three main reasons for this choice:

Because other languages say so.

C++ and Java are inspirational languages for C#, and it makes sense to observe the same overloading rules as those languages. As to why it is this way in these languages, I don't know. I found a similar question on SO about C++, although no answer is given as to why it is this way (outside of "the standard says so").

Because it creates ambiguity that need to be resolved.

As others and OP noted, allowing the same signatures excepted for the static keyword forces the user to call the methods in an unambiguous way (by prefixing the class name or the instance name). This adds a level of complexity to the code. Of course this can already be done with fields and parameters. However some don't agree with this usage and prefer to choose different names (prefixing the fields with _ or m_) for the fields.

Because it does not make a lot of sense in OOP.

This is really my understanding here, so I could be completely wrong (at least @user2864740 thinks that the argument is dubious -- see comments), but I feel like static members are a way to introduce "functional programming" in OOP. They are not bound to a specific instance, so they don't modify the internal state of an object (if they modify the state of another object, then they should be a non-static method of this other object), in a way they are "pure". Therefore I don't understand how a "pure function" could be semantically close enough of a regular object method so that they would share the same name.

Community
  • 1
  • 1
dureuill
  • 2,526
  • 17
  • 24
  • Nice! As for `Without the help of somebody who participated to the language's design, all we can do is speculate about the reasons` [this answer from Eric Lippert](http://stackoverflow.com/questions/4909156/why-arent-c-sharp-static-class-extension-methods-supported/4914207#4914207) might shred some light. However, I truly believe it's not the case for this particular question, and I totally agree with your `Because it doesn't make a lot of sense` argument. – Michael Sep 10 '14 at 09:28
  • Static members have nothing to do with "functional programming". If this were the case, then every C function relates to "functional programming". Having a static method says nothing about it's [purity](http://en.wikipedia.org/wiki/Pure_function), just that it cannot have associated instance variables (which could be immutable anyway and thus free of the "hidden information or state that may change as program execution proceeds" clause, further weakening the argument). The restriction (of not allowing a static a non-static method with the same signature) is also orthogonal. – user2864740 Sep 10 '14 at 09:52
  • @user2864740 While I do agree that *by definition*, static methods have nothing to do with purity, my claim is that, in good OOP design, static methods *should* be pure, because if they rely on a state, they should be non static methods of the object they modify. C lacks language constructs to declare instance methods (or "methods" at all, BTW), therefore we have no alternative to using both pure and non pure functions in the design. I'm not saying either that non static methods *cannot* be pure. Then again, I *could* be wrong, but I fail to see how your comment proves that fact. – dureuill Sep 10 '14 at 10:20
  • There is *nothing* in the language wrt `static` that somehow imparts any additional "functional programming" or purity. Such arguments used to justify a related benefit or imply this played a role in the inclusion of such a construct seems dubious. (There is something to be said about choosing *different* and *meaningful* method names, but that is not a justifiable cause alone.) – user2864740 Sep 10 '14 at 10:28
  • Eric Gunnerson, who worked on the language design team, said it was made illegal because otherwise it would introduce “considerable potential for confusion on the part of the user.” See my answer for his full answer. – Rashad Saleh Sep 01 '19 at 12:50
2

i) Problem hypothesis - obtain the following behavior :

  1. Be able to call a static method off of a class: e.g. MyClass.MySpecialMethod()
  2. Also be able to call a non-static method with the same return type, name and arguments off of an instance of the same class: e.g. instanceOfMyClass.MySpecialMethod()

ii) Context :

  1. Reproduce the behavior inside an application that uses Dependency Injection.

Most of today's programming uses DI - it is almost an anti-pattern to call a non-static method off of a direct instance of a dependency (without that dependency having been previously injected with DI).

iii) Solution :

class Program
{
    static void Main(string[] args)
    {
        // instead of class initialization we would have these registrations, e.g.:
        // diContainer.Resolve<IMyApplication>().With<MyDIApplication>();
        // diContainer.Resolve<ITerminator>().With<Terminator>();
        IMyApplication app = new MyDIApplication(new Terminator());

        app.Run();
    }

    public interface IMyApplication { void Run(); }
    public class MyDIApplication : IMyApplication
    {
        private readonly ITerminator terminator;

        public MyDIApplication(ITerminator terminatorDependency)
        {
            this.terminator = terminatorDependency;
        }

        public void Run()
        {
            terminator.Terminate(); // instance method call
            Terminator.Terminate(); // static method call
        }
    }

    public interface ITerminator { void Terminate(); }

    public class Terminator : ITerminator
    {
        public static void Terminate() => Console.WriteLine("Static method call.");
        void ITerminator.Terminate() => Console.WriteLine("Non-static method call.");
    }
}

Conclusion:

Yes, the signatures of the two Terminate methods are not identical, because the non-static method is an explicit implementation of the interface which does not conflict with the static method,

But in truth, when using this solution in the context of dependency injection, what we really care about is the outcome, not the plumbing - which is that we managed to call a static method off a class, with practically the same return, name and args as a non-static method off an instance of that class injected with DI.

Quantum_Joe
  • 181
  • 5
1

The same question was asked to Eric Gunnerson, who worked on the C# language design team, and his answer was:

It is true that there would be no ambiguity between the two functions as far as a compiler is concerned. There would, however, be a considerable potential for confusion on the part of the user. It would be tough to find the right method in documentation, and once you did, hard to be sure that you are calling the right version (ie you could accidentally call the static version when you wanted the instance version).

Therefore, the reason it is not allowed is by design.

Rashad Saleh
  • 2,686
  • 1
  • 23
  • 28
  • 2
    I realize this question is just passing on an answer, but honestly the answer (even from C# design team member) is pretty weak. Otherwise there would be no overloads, no hiding members, not interface implementations with duplicate names. There would be no parameters with the same name as class properties. There would be no "using" keyword to import namespaces lest there be confusion about classes with the same name. I could go on and on. In all such cases there are either warnings and/or errors AND a way to resolve the conflict! Those same solutions could be implement in this case! – C Perkins May 15 '20 at 19:25
-1

Check out this simple pseudo-code:

class A
{
  public void B(){...}
  public static void B(){...}
}

...

A A = new A();
A.B();  // <== which one is going to be called?
Mohammad Mirmostafa
  • 1,720
  • 2
  • 16
  • 32
  • 1
    -1, Not really.`class A { void Foo() {} } class B { static void Foo() {} } ` ... `A B = new A(); B.Foo(); // Which one is going to be called? Its A.Foo()!` Now to call B.Foo() `MyNamespace.B.Foo();` – Simon Farshid Sep 10 '14 at 06:51
  • Compiler never trusts developers. You are a professional developer and don't use a variable name, as the class name. Are you sure no one else will do it? – Mohammad Mirmostafa Sep 10 '14 at 06:53
  • 3
    @SepehrFarshid - That is a completely different example to what this answer shows. – Sayse Sep 10 '14 at 06:54
  • 5
    But it shows that this example proves nothing. I just did the same thing and showed you how the compiler behaved. In the example above, `A.B()` could call the non-static method, while `Namespace.A.B()` could call the static method. – Simon Farshid Sep 10 '14 at 06:56