(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.
Keep in mind the majority of people are employees, and thus don't live in a world where they need to care about making a profit. They show up at work, do their thing, and go home, never really giving a thought to how the whole process works. And while very smart, a lot of techies are positively ignorant about business, and often blinded by dogma.
You are right, of course, making x-platform software of that scale is not a simple thing. Particularly when you arent a company that has many dozens of developers and millions of users. And its not just technical limitations. Its all about cost vs benefit. Yes, you could spend then next year porting the app to Linux (despite, as you note, it already being runable in WINE). Of course, that year of development time doesnt come free. And in the end, will net you maybe an additional 5-15% users (based on your estimate). Or you can take the same money/effort, and focus it into your Windows development as a new version, or put it all into marketing, and add 50% to your user base. Which sounds like the smart choice? (obviously the numbers need to be customized to your company, and the final outcome may favor porting).
I dont know if that will help persuade 'true believers', but its the smart business move. And if you dont make smart business moves, you're out of business. And then there wont be a Linux version for sure.
Best Answer
Virtual methods are commonly implemented via so-called virtual method tables (vtable for short), in which function pointers are stored. This adds indirection to the actual call (gotta fetch the address of the function to call from the vtable, then call it -- as opposed to just calling it right ahead). Of course, this takes some time and some more code.
However, it is not necessarily the primary cause of slowness. The real problem is that the compiler (generally/usually) cannot know which function will be called. So it can't inline it or perform any other such optimizations. This alone might add a dozen pointless instructions (preparing registers, calling, then restoring state afterwards), and might inhibit other, seemingly unrelated optimizations. Moreover, if you branch like crazy by calling many different implementations, you suffer the same hits you'd suffer from branching like crazy via other means: The cache and branch predictor won't help you, the branches will take longer than a perfectly predictable branch.
Big but: These performance hits are usually too tiny to matter. They're worth considering if you want to create a high-performance code and consider adding a virtual function that would be called at alarming frequency. However, also keep in mind that replacing virtual function calls with other means of branching (
if .. else
,switch
, function pointers, etc.) won't solve the fundamental issue -- it may very well be slower. The problem (if it exists at all) isn't virtual functions but (unnecessary) indirection.Edit: The difference in the call instructions is described in other answers. Basically, the code for a static ("normal") call is:
A virtual call does exactly the same thing, except that the function address is not known at compile time. Instead, a couple of instructions ...
As for branches: A branch is anything which jumps to another instruction instead of just letting the next instruction execute. This includes
if
,switch
, parts of various loops, function calls, etc. and sometimes the compiler implements things that don't seem to branch in a way that actually needs a branch under the hood. See Why is processing a sorted array faster than an unsorted array? for why this may be slow, what CPUs do to counter this slowdown, and how this isn't a cure-all.