improve.dk
Just another mindless drone looking for the perfect stack
posts - 227, comments - 489

I don't like static methods

Written on October 16, 2008 by Mark S. Rasmussen in Development: .NET

Inspired by a recent question on StackOverflow, I felt like sharing my thoughts on static methods in general.

I used to love utility classes filled up with static methods. They made a great consolidation of helper methods that would otherwise lie around causing redundancy and maintenance hell. They're very easy to use, no instantiation, no disposal, just fire'n'forget. I guess this was my first unwitting attempt at creating a service oriented architecture - lots of stateless services that just did their job and nothing else. As a system grows however, dragons be coming.

Polymorphism

Say we have the method UtilityClass.SomeMethod that happily buzzes along. Suddenly we need to change the functionality slightly. Most of the functionality is the same, but we have to change a couple of parts nonetheless. Had it not been a static method, we could make a derivate class and change the method contents as needed. As it's a static method, we can't. Sure, if we just need to add functionality either before or after the old method, we can create a new class and call the old one inside of it - but that's just gross.

Interface woes

Static methods cannot be defined through interfaces for logic reasons. And since we can't override static methods, static classes are useless when we need to pass them around by their interface. This renders us unable to use static classes as part of a strategy pattern. We might patch some issues up by passing delegates instead of interfaces.

Testing

This basically goes hand in hand with the interface woes mentioned above. As our ability of interchanging implementations is very limited, we'll also have trouble replacing production code with test code. Again, we can wrap them up but it'll require us to change large parts of our code just to be able to accept wrappers instead of the actual objects.

Fosters blobs

As static methods are usually used as utility methods and utility methods usually will have different purposes, we'll quickly end up with a large class filled up with non-coherent functionality - ideally, each class should have a single purpose within the system. I'd much rather have a five times the classes as long as their purposes are well defined.

Parameter creep

To begin with, that little cute and innocent static method might take a single parameter. As functionality grows, a couple of new parameters are added. Soon further parameters are added that are optional, so we create overloads of the method (or just add default values, in languages that support them). Before long, we have a method that takes 10 parameters. Only the first three are really required, parameters 4-7 are optional. But if parameter 6 is specified, 7-9 are required to be filled in as well... Had we created a class with the single purpose of doing what this static method did, we could solve this by taking in the required parameters in the constructor, and allowing the user to set optional values through properties, or methods to set multiple interdependent values at the same time. Also, if a method has grown to this amount of complexity, it most likely needs to be in its own class anyways.

Demanding consumers to create an instance of classes for no reason

One of the most common arguments is, why demand that consumers of our class create an instance for invoking this single method, while having no use for the instance afterwards? Creating an instance of a class is a very very cheap operation in most languages, so speed is not an issue. Adding an extra line of code to the consumer is a low cost for laying the foundation of a much more maintainable solution in the future. And finally, if you want to avoid creating instances, simply create a singleton wrapper of your class that allows for easy reuse - although this does make the requirement that your class is stateless. If it's not stateless, you can still create static wrapper methods that handle everything, while still giving you all the benefits in the long run. Finally, you could also make a class that hides the instantiation as if it was a singleton: MyWrapper.Instance is a property that just returns new MyClass();

Only a Sith deals in absolutes

Of course, there are exceptions to my dislike of static methods. True utility classes that do not pose any risk to bloat are excellent cases for static methods - System.Convert as an example. If your project is a one-off with no requirements for future maintenance, the overall architecture really isn't very important - static or non static, doesn't really matter - development speed does, however.

Standards, standards, standards!

Using instance methods does not inhibit you from also using static methods, and vice versa. As long as there's reasoning behind the differentiation and it's standardised. There's nothing worse than looking over a business layer sprawling with different implementation methods.

Feedback

Gravatar

Kris Vandermotten wrote on 10/16/2008 7:47 PM

Mark,

You make a lot of valid points there. I'd like to add a few.

1) Overload explosion
Take an example: the FolderBrowserDialog class in System.Windows.Forms. This class really has only one important method: ShowDialog. Conceptually, this method takes a lot of parameters, all of them optional. One parameter is implemented as a physical parameter (with an overload): the owner of the dialog box. All of the other conceptual parameters are passed as properties to the object. Let's just take the most commonly used: Description, RootFolder, SelectedPath and ShowNewFolderButton. With the owner, that's five parameters. If we use overloads to supply default values, that 2^5 = 32 overloads. That's a lot.
But it really explodes when you realize that two of those are of type string: Description and SelectedPath. So how do you create the two overloads that have just the description parameter and just the selectedPath parameter? Answer: you can't.

2) Multiple return values and ref parameters
Take the same example: SelectedPath provides input (which folder is selected when the dialog box opens), but also output (which folder was selected by the user in the dialog box). And we can't return the SelectedPath, because we have a return value already (DialogResult). We could of course state that a null value being returned means the dialog box was cancelled, but that's ugly and it doesn't scale. We could use a ref parameter, equally ugly. Or we could create a new type with multiple properties to hold all of the return values. But then we might just as well make the method an instance method.

Gravatar

Kris Vandermotten wrote on 10/16/2008 7:48 PM

(continued from previous comment)

3) Designer support
Same example again: I can't drag and drop a static method on a designer (such as the Forms designer). I can do that with the FolderBrowserDialog, because it inherits from Component. That allows setting the parameters as properties in the designer. But it also allows for more complex stuff such as data binding in the designer. Talking of which:

4) Data binding
Properties can support data binding. Method parameters cannot.

A lot of arguments against static methods. And yet, I would not go as far as you did, saying you dislike static methods. I think they have their uses. You mention one: helper classes like System.Convert. I'd like to add the example of System.Math. That being said, both of those would probably be implemented as static classes with extention methods these days (like System.Linq.Enumerable).
Another example is factory methods. If you just need factories, but not abstract factories, static Create methods on the class being created are just fine. Example: XmlReader.Create, HashAlgorithm.Create, etc. Note that Parse methods (e.g. on Int32, DateTime etc) in a way are factories too, just like conversion operators. All of these are static.

Anyway, just my two cents.
Gravatar

Brian wrote on 12/2/2008 2:41 PM

Most of your points are valid, but I would still not go as far as avoiding static methods entirely. If nothing else static methods are useful for implementing extension methods, which in turn can be used to provide implementations for interfaces which e.g. LINQ uses to great effect.

Static methods are also needed for Factory methods. Since the language doesn't provide any other means to centralize object creation this feature is vital imo.

Furthermore since all classes are not sealed per default we'll often end up with types which are a little slower than they really need to be due to late binding. Statics on the other hand can always be called as fast as possible. Admittedly, this is not a big issue.

But all in all, I agree that static methods are often the result of incomplete design. People tend to build generic helper classes with misc. neat methods many of which would be much better off as members of a dedicated class.
Gravatar

Jens Mikkelsen wrote on 2/3/2009 1:20 PM

"And finally, if you want to avoid creating instances, simply create a singleton wrapper of your class that allows for easy reuse"

Welcome to the anti-pattern no. 1. :)

IMO: Avoid static methods when they are not required and don't use a patterns for something its not meant for...

Post Comment

Name  
Email
Url
Comment
Please add 5 and 7 and type the answer here: