16

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?

PixelArtDragon
  • 370
  • 2
  • 10
  • 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 06 '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 06 '16 at 18:19
  • @CodesInChaos Python has something similar, but I don't know if they're overrideable. (This seems to be common in programming languages with metaclasses, as Erik Eidt points out.) – JAB Sep 06 '16 at 19:53
  • 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 06 '16 at 19:56
  • @LightnessRacesinOrbit - You should provide an alternate answer here: http://stackoverflow.com/questions/14892847/what-does-static-variable-in-general-mean-for-various-programming-language-and-c – JeffO Sep 06 '16 at 20:49
  • 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 06 '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 06 '16 at 21:11
  • @CodesInChaos: That is a good point; people normally think of static methods as class methods, but there is no *requirement* that a method associated with a class be always dispatched statically. – Eric Lippert Sep 06 '16 at 21:32
  • @JeffO: No need; the accepted answer backs me up. – Lightness Races in Orbit Sep 06 '16 at 21:48

5 Answers5

15

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.

Erik Eidt
  • 33,282
  • 5
  • 57
  • 91
  • 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 06 '16 at 20:29
  • @Garan, See my addendum. – Erik Eidt Sep 06 '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 07 '16 at 04:50
  • @hobbs; agreed, self.staticMethod() should be treated exactly the same as this.instanceMethod() and have the same call resolution – Pierre Arlaud Sep 07 '16 at 09:11
  • 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 07 '16 at 15:03
  • @hobbs, the OP observes that C#, Java and C++ do not support `override` on static methods, and ask why not? My answer is that if we turn on overrides for static methods, say in C#, *without doing any other coordinated changes to the language*, the result will be architecturally unsound, which I explain, among other things, that without an entity that represents the class (in the static method feature) there is a lack of control over the overrides. – Erik Eidt Sep 07 '16 at 15:03
  • @hobbs, I further offer that my preferred solution to regain architectural soundness would be to cherry pick the metaclasses feature from other languages. I also suggest that this is not necessarily the only possible solution, but suspect that other solutions will bear resemblance to metaclasses, in particular that of changing class method invocation from static non-virtual call into virtual dispatch from an entity that represents the class. – Erik Eidt Sep 07 '16 at 15:05
  • @PierreArlaud, C#, Java, and C++ do not have a `self.staticMethod()`. You are proposing a set of coordinated changes to address the solution, and I might argue that such a proposal bears an emerging resemblance to the metaclass feature of other languages, and my follow on would be hence why not just adopt metaclasses for real? Metaclasses have been around in SmallTalk (~ early 70's). Metaclasses nicely unify class and instance method dispatch, so I guess I don't understand the theoretical resistance (to a fuller metaclass feature). – Erik Eidt Sep 07 '16 at 15:11
  • @Garan: the thing is that simply what we understand under the term "overriding" is a *dynamic* feature, and static methods are *static* by definition – that's why they are *called* "static". So, you can't simply "override" them, because what we mean by the term "overriding" doesn't make sense. You would either have to give up the "staticness" or define a completely new notion of what "to override" means. These ideas are fundamentally incompatible by definition. Asking why static methods aren't overridable is like asking why a tricycle can't have four wheels. Now, if you want to define … – Jörg W Mittag Sep 07 '16 at 19:08
  • … something which is similar to "overriding", but makes sense for something which is similar to a "static method", then you will have to figure out, define, and specify semantics for that feature and have to implement it. What Erik is arguing, is that anything you can come up with, will be similar enough to metaclasses that you might just as well just add metaclasses to your language. Think about the complexity. Take Java for example. A hypothetical Java+overridablestatics needs to modify one existing and one completely new concept to the language: static methods need to be modified, and … – Jörg W Mittag Sep 07 '16 at 19:11
  • 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 07 '16 at 19:13
10

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.

Mason Wheeler
  • 82,151
  • 24
  • 234
  • 309
  • 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 06 '16 at 20:23
  • Just to be clear, are you saying that in Python or Delphi, you can override class methods? – Erik Eidt Sep 06 '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 06 '16 at 21:06
  • So, these languages are providing some kind of notion of metaclasses, no? – Erik Eidt Sep 06 '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 06 '16 at 21:17
  • @ErikEidt you don't need metaclasses, just any way to get a handle on a class (for instance Perl 5 supports the same thing as Python, without a true built-in metaclass system, but it passes the *name* of a class to class methods, and supports invoking methods on a class given its name). In fact, I'm not convinced that even *that* is necessary, but it does enhance the usefulness of the feature. – hobbs Sep 07 '16 at 04:47
  • 1
    @Jerry101: just to clarify: Self doesn't have metaclasses, because it even goes one step further: it doesn't have classes at all. Instead of just unifying the idea of instance methods and class methods by making classes objects and instances of metaclasses, it also unifies the idea of objects and classes by allowing objects to inherit from objects. – Jörg W Mittag Sep 07 '16 at 19:16
  • @JörgWMittag Thanks for the explanation about Self, I should definitely look at this language. – Géry Ogam May 24 '21 at 00:53
  • FYI, in Python the receiver parameter is conventionally called `cls` rather than `self` which is used for instance methods. Also, in Python static methods can be overridden. – Géry Ogam May 24 '21 at 00:55
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.

candied_orange
  • 102,279
  • 24
  • 197
  • 315
  • 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 06 '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 06 '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 06 '16 at 20:54
  • 1
    "Nothings going to break because you have a stateless object flying around." ++++++ – RubberDuck Sep 07 '16 at 00: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 07 '16 at 00:52
  • Yeah, I don't think there's anything wrong with your answer. I was just nitpicking at that particular point because I found it interesting to point out that some things are just arbitrarily chosen in a language's design. – Theodoros Chatzigiannakis Sep 07 '16 at 07:28
3

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.)

Jörg W Mittag
  • 101,921
  • 24
  • 218
  • 318
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.

user276648
  • 111
  • 2