13

In answers to this question, the general consensus was that static methods are not meant to be overridden (and thus static functions in C# cannot be virtual or abstract). This is not only the case in C#, though; Java also forbids this and C++ doesn't seem to like it either. However, I can think of many examples of static functions that I'd want to override in a child class (for example, factory methods). While in theory, there are ways to get around them, none of them are clean or simple.

Why shouldn't static functions be overrideable?

  • 4
    Delphi supports class methods, which are pretty similar to static methods and can be overridden. They get passed a self pointer that points to the class and not to an instance of the class. – CodesInChaos Sep 6 '16 at 18:12
  • One definition of static is: lacking change. I'm curious why you made a function static that you want to override. – JeffO Sep 6 '16 at 18:19
  • 4
    @JeffO: That English definition of "static" has absolutely nothing to do with the unique semantics of static member functions. – Lightness Races in Orbit Sep 6 '16 at 19:56
  • 5
    Your question is "why should static methods use statically-typed dispatch instead of single-virtual dispatch?" When you phrase the question that way I think it answers itself. – Eric Lippert Sep 6 '16 at 21:01
  • 1
    @EricLippert The question might better be phrased as "Why does C# offer static methods instead of class methods?", but it's still a valid question. – CodesInChaos Sep 6 '16 at 21:11
14

With the static methods, there is no object to provide proper control of the override mechanism.

The normal class/instance virtual method mechanism allows for finely tuned control of overrides as follows: each real object is an instance of exactly one class. That class determines the behavior of the overrides; it always gets the first crack at virtual methods. It can then choose to call parent method at the right time for it's implementation. Each parent method then also gets its turn to invoke its parent method. This results in a nice cascade of parent invocations, which accomplishes one of the notions of reuse of code that object orientation is known for. (Here the base/super classes' code are being reused in a relatively complex way; another orthogonal notion of code reuse in OOP is simply having multiple object of the same class.)

Base classes can get reused by various subclasses, and each can coexist comfortably. Each class that is used to instantiate objects dictating its own behavior, peacefully and simultaneously coexisting with the others. The client has control over which behaviors it wants and when by choosing which class to use to instantiate an object and pass around to others as desired.

(This is not a perfect mechanism, as one can always identify capabilities that are not supported, of course, which is why patterns like factory method and dependency injection are layered on top.)

So, if we were to make an override capability for statics without changing anything else, we would have difficulty ordering the overrides. It would be hard to define a limited context for the applicability of the override, so you would get the override globally rather than more locally like with objects. There is no instance object to switch the behavior. So, if someone invoked the static method that happened to have been overridden by another class, should the override get control or not? If there are multiple such overrides, who gets control first? second? With instance object overrides, these questions all have meaningful and well-reasoned answers, but with statics they do not.

Overrides for statics would be substantially chaotic, and, things like this have been done before.

For example, the Mac OS System 7 and prior used a trap patching mechanism for extending the system by getting control of application-made system calls before the operating system. You could think of the system call patch table as an array of function pointers, much like a vtable for instance objects, except that it was a single global table.

This caused untold grief for programmers because of the unordered nature of the trap patching. Whoever got to patch the trap last basically won, even if they didn't want to. Each patcher of the trap would capture the previous trap value for a sort-of parent call capability, which was extremely fragile. Removing a trap patch, say when you no longer needed to know about a system call was considered bad form as you didn't really have the information needed to remove your patch (if you did it you would also unpatch any other patches that had followed you).

This is not to say that it would be impossible to create a mechanism for overrides of statics, but what I would probably prefer to do instead is turn the static fields and static methods into instances fields and instance methods of metaclasses, so that the normal object orientation techniques would then apply. Note that there are systems that do this as well: CSE 341: Smalltalk classes and metaclasses; See also: What is the Smalltalk equivalent of Java's static?


I'm trying to say that you would have to do some serious language feature design to make it work even reasonably well. For one example, a naive approach was done, did limp along, but was very problematic, and arguably (i.e. I would argue) architecturally flawed by providing an incomplete and difficult to use abstraction.

By the time you're done designing the static overrides feature to work nicely you might have just invented some form of metaclasses, which is a natural extension of OOP into/for class-based methods. So, there is no reason not to do this -- and some languages actually do. Perhaps it is just a bit more of a fringe requirement that a number of languages choose not to do.

  • If I'm understanding correctly: it's not a matter of whether theoretically you would or should want to do something like this, but more that programmatically, the implementation of it would be hard and not necessarily useful? – PixelArtDragon Sep 6 '16 at 20:29
  • @Garan, See my addendum. – Erik Eidt Sep 6 '16 at 20:45
  • 1
    I don't buy the ordering argument; you get the method provided by the class you called the method on (or the first superclass that provides a method according to your language's chosen linearization). – hobbs Sep 7 '16 at 4:50
  • 1
    @PierreArlaud: But this.instanceMethod() has dynamic resolution, so if self.staticMethod() has the same resolution, namely dynamic, it wouldn't be a static method anymore. – Jörg W Mittag Sep 7 '16 at 15:03
  • 1
    overriding semantics for static methods need to be added. A hypothetical Java+metaclasses doesn't need to add anything! You just make classes objects, and static methods then become regular instance methods. You don't have to add something to the language, because you only use concepts that are already there: objects, classes, and instance methods. As a bonus, you actually get to remove static methods from the language! You are able to add a feature by removing a concept and thus complexity from the language! – Jörg W Mittag Sep 7 '16 at 19:13
9

Overriding depends on virtual dispatch: you use the runtime type of the this parameter to decide which method to call. A static method has no this parameter, so there's nothing to dispatch on.

Some languages, notably Delphi and Python, have an "in-between" scope that allows for this: class methods. A class method is not an ordinary instance method, but it's not static either; it receives a self parameter (amusingly, both languages call the this parameter self) that's a reference to the object type itself, rather than to an instance of that type. With that value, now you have a type available to do virtual dispatch on.

Unfortunately, neither the JVM nor the CLR has anything comparable.

  • Is it the languages that use self that have classes as actual, instantiated objects with overridable methods -- Smalltalk of course, Ruby, Dart, Objective C, Self, Python? Compared to the languages that take after C++, where classes are not first class objects, even if there's some reflection access? – Jerry101 Sep 6 '16 at 20:23
  • Just to be clear, are you saying that in Python or Delphi, you can override class methods? – Erik Eidt Sep 6 '16 at 20:49
  • @ErikEidt In Python, pretty much everything is overrideable. In Delphi, a class method can be explicitly declared virtual and then overridden in a descendant class, just like instance methods. – Mason Wheeler Sep 6 '16 at 21:06
  • So, these languages are providing some kind of notion of metaclasses, no? – Erik Eidt Sep 6 '16 at 21:08
  • 1
    @ErikEidt Python has "true" metaclasses. In Delphi, a class reference is a special data type, not a class in and of itself. – Mason Wheeler Sep 6 '16 at 21:17
3

You ask

Why shouldn't static functions be overrideable?

I ask

Why should functions you wish to override be static?

Certain languages force you to start the show in a static method. But after that you really can solve a great many problems without any more static methods at all.

Some people like to use static methods anytime there is no dependence on state in an object. Some people like to use static methods for construction of other objects. Some people like to avoid static methods as much as possible.

None of these people are wrong.

If you need it to be overridable just stop labeling it static. Nothings going to break because you have a stateless object flying around.

  • If the language supports structs, then a unit type can be a zero-sized struct, which is passed to the logical entry method. The creation of that object is an implementation detail. And if we start talking about implementation details as the actual truth, then I think you also need to consider that in a real-world implementation, a zero-sized type doesn't have to be actually instantiated (because no instructions are needed to load it or store it). – Theodoros Chatzigiannakis Sep 6 '16 at 20:19
  • And if you're talking even more "behind the scenes" (e.g. at the executable level), then the environment arguments could be defined as a type in the language and the "real" entry point of the program could be an instance method of that type, acting on whatever instance was passed to the program by the OS loader. – Theodoros Chatzigiannakis Sep 6 '16 at 20:20
  • I think it depends on how you look at it. For example, when a program is started, the OS loads it into memory and then goes to the address where the program's individual implementation of the binary entry point resides (e.g. the _start() symbol on Linux). In that example, the executable is the object (it has its own "dispatch table" and everything) and the entry point is the dynamically dispatched operation. Hence, a program's entry point is inherently virtual when viewed from the outside and it can easily be made to look virtual when viewed from the inside as well. – Theodoros Chatzigiannakis Sep 6 '16 at 20:54
  • 1
    "Nothings going to break because you have a stateless object flying around." ++++++ – RubberDuck Sep 7 '16 at 0:00
  • @TheodorosChatzigiannakis you make a strong argument. if nothing else you've convinced me the line doesn't inspire the line of thought I intended. I was really trying to give people permission to shrug off some some of the more habitual practices that they blindly associate with static methods. So I've updated. Thoughts? – candied_orange Sep 7 '16 at 0:52
2

Why shouldn't static methods be able to be overrideable?

It's not a question of "should".

"Overriding" means "dispatch dynamically". "Static method" means "dispatch statically". If something is static, it cannot be overridden. If something can be overridden, it isn't static.

Your question is rather akin to asking: "Why shouldn't tricycles be able to have four wheels?" The definition of "tricycle" is that has three wheels. If it's a tricycle, it can't have four wheels, if it has four wheels, it can't be a tricycle. Likewise, the definition of "static method" is that it is statically dispatched. If it's a static method, it can't be dynamically dispatched, if it can be dynamically dispatched, it can't be a static method.

It is, of course, perfectly possible to have class methods that can be overridden. Or, you could have a language like Ruby, where classes are objects just like any other object and thus can have instance methods, which completely eliminates the need for class methods altogether. (Ruby only has one kind of methods: instance methods. It has no class methods, static methods, constructors, functions, or procedures.)

1

thus static functions in C# cannot be virtual or abstract

In C#, you always call static members using the class, eg BaseClass.StaticMethod(), not baseObject.StaticMethod(). So eventually, if you have ChildClass inheriting from BaseClass and childObject an instance of ChildClass, you will not be able to call your static method from childObject. You will always need to explicitly use the real class, so a static virtual just doesn't make sense.

What you can do is redefine the same static method in your child class, and use the new keyword.

class BaseClass {
    public static int StaticMethod() { return 1; }
}

class ChildClass {
    public static new int StaticMethod() { return BaseClass.StaticMethod() + 2; }
}

int result;    
var baseObj = new BaseClass();
var childObj = new ChildClass();

result = BaseClass.StaticMethod();
result = baseObj.StaticMethod(); // DOES NOT COMPILE

result = ChildClass.StaticMethod();
result = childObj.StaticMethod(); // DOES NOT COMPILE

If it were possible to call baseObject.StaticMethod(), then your question would make sense.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.