6

For a current project I have created a Console class which wraps up C++'s usual cout, writes output to a file or uses Console::WriteLine depending on the environment. Currently I've setup my code base to inject a console object into each class that I use, making all of them extend a base class: Debuggable. This seemed like a great plan at first but now that I have to pass the console to every object and ensure that it is created before all of them I'm having second thoughts.

Usually consoles seem to be handled with static objects, so I'm considering changing my implementation to use a static instance of the console that all the objects can use but I feel that this removes an element of control, I can't have more than one potential console with different formats and targets.

I understand that there's a lot of discussion about dependency injection, I'm interested specifically in the case of utilities such as a console.

sydan
  • 373
  • 1
  • 4
  • 11
  • If it contains the word 'static' in it, it is wrong. – Mike Nakis Apr 27 '15 at 09:35
  • 7
    @MikeNakis: Ergo, your sentence is wrong. – Robert Harvey Apr 27 '15 at 09:36
  • 1
    @MikeNakis many of the standard library implementations for things involve static objects... I know static is frowned upon but it's often hard (or excessively time consuming/fragile) to do things any other way. I personally feel static can be happily used when the static function or object is deterministic or constant. Not so certain whether a console object is either of these. – sydan Apr 27 '15 at 09:43
  • @RobertHarvey lol! – Mike Nakis Apr 27 '15 at 09:57
  • @sydan yes, of course, I was exaggerating. I am addressing precisely this question about the nature of the console object in my answer below. – Mike Nakis Apr 27 '15 at 09:57
  • There is an interesting article on this topic in Overload Journal #126 - April 2015: [Alternatives to Singletons and Global Variables](http://accu.org/index.php/journals/2085). – manlio Apr 28 '15 at 14:22

2 Answers2

2

Usually when there is an object, which needs to be used everywhere (like your logger class), then using the singleton makes sense. And that is one of rare cases where the singleton is not an anti pattern.

You can implement it in such case that it is possible to create a mock (if you going to unit tests).

So, something like this :

class Logger
{
public:

    typedef Debugable* (Fnc)();

    static Debugable& Instance()
    {
        static Debugable* p = f();
        return *p;
    }

    void SetCreator( Fnc newf ){ f = newf; }


private:
    static Debugable* DefaultCreator(){ return 0; }
    static Fnc f = DefaultCreator();
};

First you need to set the creator function somewhere (do this only once) :

Debugable* CreateLogger()
{
   return new StdOutputLogger;
};

//...
// somewhere
Logger::SetCreator( CreateLogger );

then use it as a singleton : Logger::Instance() << "log this message";

In unit tests, you need to create a mock object :

struct MockLogger : public Debugable { // methods };

Set it in the setUp() function :

MockLogger mock;
Debugable* CreateMock()
{
   return new StdOutputLogger;
};

void setUp()
{
  Logger::SetCreator( CreateMock );
}

then check the accesses to the mock.

BЈовић
  • 13,981
  • 8
  • 61
  • 81
  • Hi, I'm pleased that this is a possible place for a singleton as I find them unfriendly but wish I could use them more. I will definitely need to mock them but I'm afraid I find your example a little confusing, could you possibly also post how to use this code from a simple unit test (or general external) environment? – sydan Apr 27 '15 at 09:29
  • I see, so you expose the option to define a 'creator' function that can be modified depending on the environment, if undefined nothing is returned, I guess this would be a good place for the NullObject pattern. – sydan Apr 27 '15 at 10:04
  • @sydan Actually no. I would set the default creator to the function, which creates the object doing the logging (or whatever the functionality is). I wouldn't leave it null. – BЈовић Apr 27 '15 at 12:47
1

Note: Initially I answered this question without realizing that it is about the use of singletons for debugging purposes. So, the first part of my answer is for using singletons in general, not for debugging. The second part of my answer addresses the issue of debugging. (I have added to it a couple of points I made in comments.)


Part 1 - singletons in general (without respect to debugging)

My recommendation would be to not go with a singleton. My experience is that "the singleton" is not a pattern, but an anti-pattern by its very nature. (But let's not turn this into yet one more episode of the singleton war, shall we?)

You say that you are "interested specifically in the case of utilities such as a console." I am afraid that a console is not a utility. It is a stream to which you send output.

  • Text sent to it gets buffered, so it has state.

  • Concurrently calling it from multiple threads might not crash it, but it will result in misplaced linefeeds and garbled lines, so it cannot really be thought of as amenable to multi-threading.

  • Even if it is convenient for some to think of it as a singleton, conceptually it is not, as evidenced by the fact that you can redirect it to other devices like files, printers, etc.

So, either you can treat it as what it really is, (an output stream, passed to whoever needs to output stuff,) or treat it like some special public global one-of-a-kind thing, the nature of which everyone has intimate knowledge of, and then rely on the sorcery provided by the library and the OS beneath the scenes to undo your assumptions and make it work like the output stream that it really is, as far as the rest of the system is concerned.

True, you may end up making it a singleton due to pragmatic concerns of convenience vs. correctness, but I suppose that if convenience was your primary concern then you would not be asking the question in the first place. So, this answer is to say that there do in fact exist other engineers besides you, like me, who will tenaciously pursue the "do it right, avoid singletons" approach.


Part 2 - singletons for debugging

I seem to have missed the point about debugging in the original question. When it comes to debugging, I do not have objections with the use of singletons. I would use a singleton as a debugging helper, I would not use a singleton for anything else. But then again, we do not test debugging helpers. If it requires testing, then it is not just a debugging helper.

In the past I have tried passing debugging facilities as dependencies to objects in the same way that I pass formal dependencies (dependencies that that are part of the design) and I have come to the conclusion that a) it is a big pain, b) it adds more complexity than the design calls for. When debugging dependencies are treated with the same dignity that design dependencies are treated, they start to appear as if they are part of the design, while they are not.

For example, say you have a collection which is sortable and you want to pass it a comparator. Is it really worth the hassle to make the comparator an object so that you can inject the debugging dependency in it? And isn't it kind of odd now that the comparator has become an entity of its own, as if it is part of the design, while in fact the only reason it is an entity is so as to have a reference to the debugging facility?

So, if it is only for debugging, (which, incidentally, means that it will not require testing,) then go ahead and use a singleton, it is fine.

Mike Nakis
  • 32,003
  • 7
  • 76
  • 111
  • 1
    If I make it an output stream given to objects who need it I still find I come up against areas where it can cause problems. For example when making a Hash function object for unordered_map, I cannot pass the console object into the function or give it to the Hash function object, so I cannot debug within this function. I agree, doing it right is the best thing to do, but it seems that the right thing is likely to make my life very hard. – sydan Apr 27 '15 at 10:00
  • I would be interested in the down-voters reasoning. – sydan Apr 27 '15 at 10:01
  • Oh, never mind, I knew while posting this that it will be down-voted, because people here tend to down-vote things that they do not like, not things that they have some valid engineering objection to. Anyhow, I seem to have missed the point about debugging in your original question. When it comes to debugging, I do not have such serious objections with singletons. I would use a singleton as a debugging helper, I would not use a singleton for anything else. – Mike Nakis Apr 27 '15 at 10:03
  • I think this is the crux of the matter. It is difficult to differentiate good practice between production code and debugging, especially because debugging code easily gets carried over and implementations get copied into other places. I fundamentally do not feel that dependency injection is a good fit for all cases but then static can be so dangerous and test-unfriendly. I wish there was an alternative. – sydan Apr 27 '15 at 10:06
  • I can guess why downvoted, you say " do not use singleton" followed by "use a singleton" when debugging. Its not a good answer given that the first part is very dogmatic, and the second part contradictory. Singletons have their place, and I don't see much distinction between a singleton used for debugging and a singleton used for other reasons - any issues having singleton in the code doesn't change based on its use. – gbjbaanb Apr 27 '15 at 10:51
  • @gbjbaanb The downvote was cast before I added the amendment. – Mike Nakis Apr 27 '15 at 10:52
  • Oh well, must be because of the "never use singletons" dogma. I like the stream aspect to your answer, but you don't say quite how to tie that to his problem so its useable without injecting one everywhere or using a singleton to hold it. – gbjbaanb Apr 27 '15 at 11:02
  • @gbjbaanb I did not say anything about that because I do not think that there is really anything to say that the OP does not already know: if you want to avoid making something a singleton, then you must be prepared to bite the bullet and pass it (or, have some magic dependency injection framework like spring, if available, pass it) to every single place that needs it. Yes, you don't want to do that for debugging, but you do want to do that for everything else. – Mike Nakis Apr 27 '15 at 11:09
  • Why wouldn't you want to do that for debugging? – Doval Apr 27 '15 at 12:03
  • @Doval in the past I have tried passing debugging facilities as dependencies to objects in the same way that I pass formal dependencies (dependencies that that are part of the design) and I have come to the conclusion that a) it is a big pain, b) it adds more complexity than the design calls for. When debugging dependencies are treated with the same dignity that design dependencies are treated, they start to appear as if they are part of the design, while they are not. – Mike Nakis Apr 27 '15 at 12:19
  • sydan's example is a good case in point: say, you have a collection which is sortable and you want to pass it a comparator. Is it really worth the hassle to make the comparator an object so that you can inject the debugging dependency in it? And isn't it kind of odd now that the comparator has become an entity of its own, as if it is part of the design, while in fact the only reason it is an entity is so as to have a reference to the debugging facility? – Mike Nakis Apr 27 '15 at 12:20