While developing a two-dimensional vector class as part of a math library, I'm considering having static and instance method pairs for stylistic and usability reasons. That is, two equivalent functions but one is static & non-mutating, and the other is instanced & mutating. I know I'm not the first person to consider this problem (See here, for example) but I haven't found any information that directly addresses it.
Pros of having static and instance method pairs:
It is implied that static methods are not mutating when both static and instanced methods are provided. This can make the calling code much clearer, e.g.:
someVector = Vector2d.add(vec1, vec2);
someVector = (new Vector2d(vec1)).add(vec2); // does the same thing although more convoluted.
// similarly adding directly to a vector is simpler with a mutator method.
someVector.add(vec2);
someVector = Vector2d.add(someVector, vec2);
This is especially important when long chains of function calls are used, which is common with vectors.
In-place operations can be faster computationally than creating a new instance for every operation. The user decides when performance is important. For users of a Vector class, performance may be important as vectors are frequently used in computationally expensive code.
Pros of having only static or instance methods, but not both:
No significant code redundancy. Easier to maintain.
Less bloat. The javadocs will be almost half the size.
Not necessary to inform users that static methods never mutate and non-getter instanced methods always mutate.
How frowned upon is having static/instance method pairs? Is it used in any major libraries?
Is the pattern "static methods don't mutate, instance methods do" widely known?
I think your concept of providing both static/immutable and instance/mutable methods is a good one. I think the distinction is easy to explain and will be easy for the API users to understand and remember.
I think your API implementation code will not have redundant business logic. You will find that that you repeat a pattern where the static implementation creates a new instance and calls the instance method on that new instance.
Given that I am lazy, I would look at building a bit of infrastructure that would auto-generate the static methods, their javadoc and their unit tests at compile-time. This would be overkill if you have 10 methods, but becomes a big win if you have 1,000 methods.
On the first part, "static methods don't mutate", that's widely used in OOP. I haven't heard of it being expressed explicitly. But it is common sense: "If you change an object, why would the method be static if it could be an instance method?" So I completely agree with the "static methods don't mutate".
On the second part, "instance methods do [mutate]", that's actually not as widely used. It rather depends on whether you decide your design to apply immutability or mutability. Examples from the Java API: java.lang.String
is immutable, java.util.Date
is mutable (most likely by accident / bad design), java.lang.StringBuilder
is mutable intentionally (that's its purpose). Mutability can lead to defensive cloning in order to protect the code from mutation bugs. Whether this really is a problem depends on a few things:
Personally, I prefer immutable objects, I'm a fan of final
(if I could change Java, I would make final
the default for all fields and variables, and introduce a keyword var
to make them non-final), and I try to do functional programming in Java, although it is not a functional programming language, as much as possible. From my experience I know that I spend significantly less time debugging my code than others (actually I run the Java debugger maybe twice a year or so). I do not have enough empirical data and proper analysis for creating any kind of "causal relationship" between experience, immutability, functional programming and correctness, therefore I will only say I believe that immutability and functional programming help for correctness, and you will have to come up with your own judgement on this.
Concluding on the second part, "instance methods do [mutate]" is the widely used assumption in case the object is mutable anyway, otherwise instance methods would clone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With