(Using Java terminology): Static methods can be associated with static members (members of the class
object). If the methods don't access static members (nor IO resources or anything else that could change state), of if those members are final
primitives or immutable objects (essentially constants), then such static methods could be called functions, but in general, because they potentially could access the class
object's members, they're usually called static methods.
In order to count as a function, a method must be independent of any state; it must not cause any side effects nor be affected by any side effects. When called with specific parameters, it must always return the same result. Otherwise it's not a pure function.
That is, the following area
is a function:
class MyClass {
static final double pi = 3.14;
static double area(double r) {
return pi * r * r;
}
}
while the following getCallCount
is not a function:
class MyClass {
static int callCount = 0;
static int getCallCount {
return ++callCount;
}
}
In general, mutable (non-final
) static members should be used with caution - someone would say that they should not be used at all - because they make a global state to the program, which likely turns out to be a bad design choice in the long run. There are exceptions, but be careful...
You don't even need static members to make static non-functions: System.nanoTime()
is definitely not a pure function (because it returns different value on successive calls), even though it only accesses the computer's clock, not any static members.
Confusingly enough, you could also make non-static pure functions:
class MyClass {
final double pi = 3.14;
double area(double r) {
return pi * r * r;
}
}
Now, although not static
any more, area
is still a pure function: it doesn't touch anything that could change. The fact that you would have to create an instance of MyClass
to access area
doesn't reduce its "functionness". Indeed, one could argue that this kind of pure functions should always be made static.
Those aren't static methods they are on the prototype. Instances of foo would be able to call static methods by just doing this.statics.method. True statics would be applied to just foo itself. It is also cleaner than putting logic in the constructor to handle statics.
function foo() {
}
foo.statics = {
}
console.log(new foo().statics)
//undefined
console.log(foo.statics)
// {}
The framework that we write in allows statics this way, it is a nice way to keep enums and constants. It also gets around problems that happen when instance sharing is not needed and non primatives are placed on prototype, which for some reason happens all of the time on SO. Problems arise during inheritance though since static methods defined this way won't be inherited. The inheritance problem mostly arises after due to parent classes having methods that do this.class.statics.staticFn
if the class is inherited from those methods won't work but that can easily be fixed.
update
Having to invoke a function to get at the statics and having logic in the constructor to have it handle and know about it having statics is bad in my opinion. The user has to know that the statics need to be accesses by invoking a function and the constructor needs to know that it has statics and to handle the case where the new operator is not used.
Problems can arise when instances don't know that they are modifying statics. In this case lets replace the name statics with config.
function foo(){
if ( !foo.prototype.config ){
foo.prototype.config = {
a: 1,
b: 2
}
}
if ( !(this instanceof foo) ){
return foo.prototype.config;
}
}
foo.prototype.foobar = function() {
this.config.a = 5;
}
foo()
>Object {a: 1, b: 2}
new foo().foobar();
foo();
> Object {a: 5, b:2}
Best Answer
I'll go with the most obvious problems of static methods with explicit "this" parameters:
You lose virtual dispatch and subsequently polymorphism. You can never override that method in a derived class. Of course you can declare a
new
(static
) method in a derived class, but any code that accesses it has to be aware of the entire class hierarchy and do explicit checking and casting, which is precisely what OO is supposed to avoid.Sort of an extension of #1, you can't replace instances of the class with an interface, because interfaces (in most languages) can't declare
static
methods.The unnecessary verbosity. Which is more readable:
Subject.Update(subject)
or justsubject.Update()
?Argument checking. Again depends on the language, but many will compile an implicit check to ensure that the
this
argument is notnull
in order to prevent a null reference bug from creating unsafe runtime conditions (kind of a buffer overrun). Not using instance methods, you'd have to add this check explicitly at the beginning of every method.It's confusing. When a normal, reasonable programmer sees a
static
method, they are naturally going to assume that it doesn't require a valid instance (unless it takes multiple instances, like a compare or equality method, or is expected to be able to operate onnull
references). Seeing static methods used this way is going to make us do a double or perhaps triple take, and after the 4th or 5th time we are going to be stressed and angry and god help you if we know your home address.It's a form of duplication. What actually happens when you invoke an instance method is that the compiler or runtime looks up the method in the type's method table and invokes it using
this
as an argument. You are basically re-implementing what the compiler already does. You're violating DRY, repeating the same parameter again and again in different methods when it's not needed.It's hard to conceive of any good reason to replace instance methods with static methods. Please don't.