16

Possible Duplicate:
What is the difference between all-static-methods and applying a singleton pattern?

In C# Static methods has long served a purpose allowing us to call them without instantiating classes. Only in later year have we became more aware of the problems of using static methods and classes.

  • They can’t use interfaces
  • They can’t use inheritance
  • They are hard to test because you can’t make mocks and stubs

Is there a better way ? Obviously we need to be able to access library methods without instantiated classes all the time otherwise our code would become pretty cluttered

One possibly solution is to use a new keyword for an old concept: the singleton. Singleton’s are global instances of a class, since they are instances we can use them as we would normal classes. In order to make their use nice and practical we'd need some syntactic sugar however

Say that the Math class would be of type singleton instead of an actual class. The actual class containing all the default methods for the Math singleton is DefaultMath, which implements the interface IMath. The singleton would be declared as

singleton Math : IMath
{
   public Math
   {
      this = new DefaultMath();
   }
}

If we wanted to substitute our own class for all math operations we could make a new class

MyMath that inherits DefaultMath, or we could just inherit from the interface IMath and create a whole new Class. To make our class the active Math class, you'd do a simple assignment

Math =  new MyMath();

and voilá! the next time we call Math.Floor it will call your method. Note that for a normal singleton we'd have to write something like Math.Instance.Floor but the compiler eliminates the need for the Instance property

Another idea would be to be able to define a singletons as Lazy so they get instantiated only when they're first called, like

lazy singleton Math : IMath

What do you think, would it have been a better solution that static methods and classes? Is there any problems with this approach?

Addendum

Some points have been raised, that one of the main benefits of static methods is having methods that are "stateless" and thus side-effect free to some extent from a concurrency point of view. I wholeheartedly agree that that's a valid point. However we're mixing two different issues and problems here: One is making some methods invokable and globally accessible without having to explicitly create an instance. The other is having methods that are stateless.

The second problem could be solved by method having something like a stateless keyword that similarily to static prevented them from calling this or perhaps do even more to enforce no side-effecs. With singletons rather than static classes and something like stateless classes and methods I think you'd have the following pro's and con's

Pro's

  • "Static" methods in other classes and framework classes could easily be designed to be overridable
  • Classes would be easier to test
  • Using instances instead of static classes means design patterns work better (things like factories)
  • No limitation on inheritance and polymorphism in contrast to static

Cons

  • Perhaps slightly worse performance?
  • Bad programmers will but everything in singletons to have them globally accessible instead of using dependency injection, perhaps you should only be able to access singleton methods and not properties/fields to avoid global variables :)
  • ?

Perhaps Math was a bad example, but imagine if the .Net string methods were inefficient, you could easily replace them with your own using this method. Or some third-party class has has a singleton method that you wanted to alter slightly, you could inherit and alter that method

Homde
  • 11,104
  • 3
  • 40
  • 68
  • 1
    I'm interested to hear about the situation in which you need to globally redefine Math.Floor() to do something other than what you'd expect it to do. – Ant Mar 10 '11 at 14:16
  • 3
    You can test global functions just fine without resorting to interfaces, instances, and mocks. In fact I would question the practice, and some call me a TDD zealot. If calling a function on `Math` is part of the algorithm of the object I have under test, then I am testing the correctness of the algorithm-- **not** whether it calls certain functions on Math. – Berin Loritsch Mar 10 '11 at 14:47
  • Math.Floor might not be the best example, but there are other framework methods you might want to override to give better performance or alter behavior slightly. – Homde Mar 10 '11 at 16:11
  • 2
    If you're trying to micro-optimise to the extent that the .NET string methods are too inefficient for you, you really shouldn't be using .NET in the first place. I think the overhead associated with inheritance chains and looking up methods within objects would probably outweigh any benefits you can make by implementing your own string class. It sounds to me like you're desperately trying to implement monkey patching in C#. – Ant Mar 11 '11 at 15:38
  • As an aside: OOP offers many useful principles for extension beyond inheritance. As the Gang of Four said, "Favor object composition over class inheritance." One way to reuse a static method in a new class is wrap the call to that method in your new class. Thus you get the benefit of inherited behavior, and since you can't use static types polymorphically, that's all the benefit you'd get from inheritance anyway. – CodexArcanum Mar 11 '11 at 16:30
  • I feel like this entire issue is getting overly complicated for no reason. Use the right tool for the right job. Static methods belong to the class, every instance should have access to them. You never need to instantiate `Math` so it makes sense to use Static members, a database manager on the other hand *might* make sense to instantiate while preventing multiple instances. – zzzzBov Mar 11 '11 at 20:50
  • You may be interested in the "Cake Pattern" -- just google it ;-) -- sometimes used with Scala's version of a Singleton which can be used compile-time DI. – pst Nov 12 '11 at 06:05

3 Answers3

15

There is no difference in the dangers by changing your static methods into instance methods on a singleton. They are effectively the same.

Sometimes you simply have functions. A function in mathematical terms, contains no state. It is simply the calculations to apply to an input to determine your output. For example, Math.Sqrt does not contain any state. It performs a calculation on the value you provide, and returns a response that is derived from that value. In C, C++, Ruby, Perl, and other languages that support simple functions you don't have to tie that function to any class, static or otherwise. In Java and C# all functions have to be tied to some class--which is technically a hack.

It's important to note that true functions are perfectly fine to remain a static method. For instance, everything in the Math class is properly defined. I don't fancy doing something stupid like Math.Instance.Sqrt(x) just to satisfy a "no static method" standard.

The truth is, your Instance property in this case would be the type of static method that causes the most problems. The reason? It's not a function--it maintains state, and changes its behavior based on the internal state. On the first access, it determines that the global instance doesn't exist so it creates it. On subsequent accesses it reuses that instance. In multi-threaded environments this can create a race condition which can potentially create multiple instances of the Math class. Eventually one will win out and remain stored, while the others get garbage collected. With the Math class the race condition would simply be an affordable inefficiency, but if the singleton needed to maintain state from all it's clients then that will be a problem. If you add locks around the singleton access, you've introduced a major performance bottleneck for multi-threaded applications that only gets worse with the number of threads. This is particularly because the lock is only needed until the instance is created.

Let your functions be as close to functions as possible, and you never need to worry about these multi-threaded singleton issues. In languages that support functions, implement them as functions. In languages that require a static method, make them a static method. Singletons introduce a number of issues that only come to light when you dig deeper into your project.

Berin Loritsch
  • 45,784
  • 7
  • 87
  • 160
  • Yeah, not sure why OO has to preclude functions. – Michael K Mar 10 '11 at 15:11
  • that could be resolved with different features, such as having a stateless keyword or having singletons being stateless per default – Homde Mar 10 '11 at 16:09
  • 2
    @MKO, I disagree. The multithreading issues only come to play _because_ you've changed the static methods to instance methods on a singleton. Why do we need a `stateless` keyword? What can the language do (practically) to enforce the statelessness of a method? – Berin Loritsch Mar 10 '11 at 16:17
  • yes but we gain being able to have proper inheritance and a host of other features by static not being a corner case. I'm not sure about the exact way to go about but a stateless method wouldn't be allowed to set any fields/properties or access any non-readonly fields and properties nor call methods that do so. – Homde Mar 10 '11 at 16:24
  • 1
    @MKO, I still don't see that we're gaining anything by going through all these changes for simple stateless functions. It's already a language hack to have to tie those functions to a class. Adding yet one more and incorporating a host of problems that can otherwise be avoided doesn't seem like a good trade-off. I fail to see how inheritance plays a part in a simple function. Perhaps a much more concrete example that clearly demonstrates the type of problem you are trying to solve. The Math example is just a horrendous over-engineering to force that in your model. – Berin Loritsch Mar 10 '11 at 19:06
  • Are you suggesting classless functions would be better? Most patterns (factories , visitors) etc depends on being able to pass along some sort of instance with the polymorphic object you want to use. That's my main gripe with static classes is that they're hard to use for things like that and depedency injection. I see your point from a functional language point of view but in OOP I still think it's pretty necessary to tie functions to an object in some manner (even if it's through delegates) – Homde Mar 11 '11 at 12:12
  • 1
    Yes, for the problem you specified: `Math` related functions, pure functions would be better. For more general needs where you need to maintain state, and do proper OO, then yes tying methods to classes is appropriate. The biggest takeaway is that you have to use the right tool for the job. What you were suggesting for the example you provided was not the right tool. What you suggested could be proper for another problem altogether. However, you can do it without a statically accessible singleton--which is no better than static methods tied to a class, and is in fact worse. – Berin Loritsch Mar 11 '11 at 12:58
  • Maybe Math was a poor example but it was more to show how one would override a framework class. But I still don't see your argument for static, if functions could be declared as stateless it would give you all of the benefits of static and none of the downsides as far as I can tell. – Homde Mar 11 '11 at 14:05
  • 1
    @MKO, I'm still lost as to what the downside of static is _in this case_. I've done nothing but demonstrate how they are superior for this case. I even demonstrated that there are **more** downsides to instance methods on a singleton. At this point, I think we will have to agree to disagree. – Berin Loritsch Mar 11 '11 at 14:26
  • yeah, but not if you count in something like stateless methods :) – Homde Mar 11 '11 at 15:04
  • 1
    @Berin Loritsch While I'd agree that being forced to put static methods on an object can at times seem like a hack, when the class itself is also static it mostly becomes a module or a namespace. Terminology aside, I don't think a static method on a static class is much different from a module full of a library methods in another language. And surely you'd want your free-standing functions grouped together somehow for ease of use and maintenance. – CodexArcanum Mar 11 '11 at 16:05
  • 1
    @CodexArcanum, I agree with that statement. I have no qualms with name spaces and modules. The only thing I have a problem with is turning them all into a statically accessible singleton. I've seen this abused and cause several more problems than they are worth. – Berin Loritsch Mar 11 '11 at 16:07
  • @Berin Loritsch Oh no, I agree with that. I think I've used a singleton once and regretted it afterwards. I've also converted a large heap of static methods into a series of objects that were kind-of injected (not true DI) into the client objects and found that to be a significant improvement. – CodexArcanum Mar 11 '11 at 16:26
  • Great point about the difference between methods and functions. Methods act on an object and the object keeps the state. Functions should never have any state (unless you're modifying globals) but when you use static classes, you can get around this by using private static members. Gives you a nice feeling that you're not using globals, but you still suffer from the same problems, that is, you can modify the global state of the app from anywhere in the app, otherwise known as the "everybody knows everybody" and "spaghetti code" anti-patterns. – Ruan Mendes Apr 04 '13 at 00:06
  • `Math.Sqrt(x)` is an example, that I have not liked in any language. Why not `var y = x.Sqrt()`? – Residuum Nov 03 '15 at 13:20
  • @Residuum: Consider the fact that you can take the square root of an int, float, double, decimal,... `x.Sqrt()` cannot use implicit vasting unless these types derive from each other (which is not a good idea), which leads to many similar-but-unrelated `Sqrt()` implementations on all number types (which then also need to be classes). While `Math.Sqrt()` still has to account for all types of numbers, its parameter can use implicit type conversion (where relevant), and otherwise define overloaded methods in the same place, i.e. the `Math` class. – Flater Apr 20 '18 at 13:32
  • 1
    @Residuum: You can still create your `x.Sqrt()` method using extension methods, if you really want to use that syntax. But it still uses `Math.Sqrt()` under the hood. – Flater Apr 20 '18 at 13:33
6

If the question is "What do we use to replace static classes?"

Singletons are not the answer.

Dependancy injection is.

That said, I'm using singletons to replace static classes in a legacy code base, in this instance it's far more achieveable to make this change than it is to add DI, and allows us get old code under test much faster. See this stack overflow question for more on this

Update
Q1: How would you use dependency injection on a framework level for things like Math and File functions?

At the framework level? Since we're allowed to add language support for Singleton we instead add support in the framework for DI in namespaces like Math, IO etc.
The machine config will provide sections that - by default - add the framework flavours of these, hooks which we can remove in app.config files and add in our own (or other ones for tests)

Q2: Also, if you could scope what class a singleton would use for different classes, wouldn't that be de facto dependency injection?

Sounds confusing to me mate, so instead of your singleton representing a single object, it now represents multiple objects and serves up different ones depending on the context of how it's called? Wouldn't that a) make it a multipleton and b) be a freaking nightmare to try and keep track of what any given Math method is going to do depending on how/where you call it.

Binary Worrier
  • 3,112
  • 2
  • 25
  • 23
  • How would you use dependency injection on a framework level for things like Math and File functions? – Homde Mar 10 '11 at 13:23
  • Also, if you could scope what class a singleton would use for different classes, wouldn't that be de facto dependency injection? – Homde Mar 10 '11 at 13:24
  • b)Normally you wouldn't much around with singleton context, it might be only a feature from testing purposes, and you don't really need it since you simply can set the singleton to what you want before and after testing – Homde Mar 10 '11 at 16:13
  • a) machine config's doesn't seem like an elegant solution for a programming language – Homde Mar 10 '11 at 16:15
  • It depends on how you look at it. Where is the best place to fix the problem, in the language, the runtime or the framework? If you've decided this is a language feature then yes, it is. If however we broaden it to "the best way to fix the problem" then framework may be the better way to go - obviously IMHO :) – Binary Worrier Mar 10 '11 at 17:27
  • 1
    I actually think singleton instead of statics would be perfect for dependency injection. Just avoid using the singleton and instead pass the interface or base class of the classes you want to use to the classes. Since Math would no longer be static that would be much more flexible and you could create an instance of DefaultMath or create your own. – Homde Mar 10 '11 at 17:52
  • About 3 or 4 months ago I code-gen'ed replacements for some of our in house static libraries (the Accessors in our DAL was one big collection of static classes) with singletons (I call them static instances). They allow us to get code under test, but have their own issues (e.g. mocks hanging around too long in tests etc) and need to be handled carefully. I'd rather get DI in there, however it's a job for another time. The singletons are vastly better than static classes, but I've found they're not the best way to solve the `static class` problem. – Binary Worrier Mar 11 '11 at 08:12
0

The question of interfacing and inheriting static classes kept me busy for a while, too, although on a theoretical level more than on a practical.

There are also a couple of questions on SO dealing with the subject.

Finally I worked out a solution that essentially consists of

  • the separation of the "real class" part and the "static class" part into 2 classes
  • a class attribute assigning a class its pseudo-static class
  • a (static) helper class retrieving and instantiating the pseudo-static class for a class

For more details, read this mini series on my blog.

devio
  • 251
  • 2
  • 3