0

I have an occasion of code in which I will draw a different set of buttons in a screen (depending on the number of the buttons). One thought (and my current implementation) is to use an action array and call a different action

        Action[] array = new Action[9];
        array[0] = one;
        array[1] = two;
        array[2] = three;
        array[3] = four;
        array[4] = five;
        array[5] = six;
        array[6] = seven;
        array[7] = eight;
        array[8] = nine;

        array[buttons.Count - 1]();

So depending on the number of buttons I call the specific drawing method. Another implementation might be using switch case and would look like something this

switch(buttons.count){
case 1: one(); break;
case 2: two(); break;
.
.
.
.
case 9: nine();break;
}

Are there any pros and cons of using versus the other? Are there any efficiency differences?

2

3 Answers 3

4

IMHO the first one is in most cases preferable. First, in C# you can rewrite the initialization much shorter as

    Action[] array = new[]{one, two, three, four, five, six, seven,eight,nine};

But the real advantage comes when you have to change your actions later, for example, by introducing an additional argument. You then have to change only this line

    array[buttons.Count - 1](myArgument);

The switch variant instead needs changes in 9 places instead:

switch(buttons.count){
case 1: one(myArgument); break;
case 2: two(myArgument); break;
...

That is because the switch variant does not follow the "Don't Repeat Yourself" (DRY) principle. Imagine what happens when you have not just 9 actions, but 50, or you have to introduce more arguments, or to process a return code from the action / function.

And don't worry too much about performance - in most real-world cases the performance difference is negligible. When you suspect it is not, you will have to try and measure if a replacement by a switch statement does really bring the necessary performance gain.

3
  • Great Scott!!! you are right :P Commented Nov 27, 2014 at 10:42
  • I object. DrawFunction getDrawFunction(int forCount) { switch (forCount) { case 1: return one; case 2: return two; ... }}; and voilà, we've build ourselves a switch statement that follows DRY. Similarly, myArgument could be a record/tuple/valueobject, so that rather than adding another argument, you would just add another field. Thirdly, you are omitting that one will have to update one through nine to start with, so on the whole, it's not 1 vs 9, but 10 vs 18, if you excuse the gross oversimplification.
    – back2dos
    Commented Nov 27, 2014 at 11:55
  • Hmmmm, I'm unsure if a jump table follows DRY any better than a switch/case. I was just asked about this and I wasn't sure. Then I found your response and I'm still not convinced that it is better or not. Yes, with a jump table, you have a call only once, but you still have to change all of the signatures. WIth a switch/case, it's possible that you can change a single signature and not affect the others if new parameter is not used in the others (not an issue in this case). I personally prefer the jump table, but YMMV in other possible jump table scenarios.
    – Adrian
    Commented Dec 8, 2015 at 21:40
3

Well, there are many arguments one way or the other.

But the most important thing to realize: it doesn't matter (in this case).

  • Performance wise, the drawing (and subsequent rendering of it) will take order of magnitudes longer than the invocation of the right drawing functions.
  • Complexity wise, the drawing code will most likely also crushingly outweigh the invocation issue. The fact that you need nine different drawing functions makes this pretty clear.

If you are actually concerned with this, the right thing to do is to blackbox the decision in a separate class, where a button count goes in and a drawing function comes out. Thus no other code depends on how this is accomplished and you can change that any time you have a reason to.

2
  • Violating the DRY principle does not matter? Sorry, but I heavily disagree.
    – Doc Brown
    Commented Nov 27, 2014 at 11:48
  • @DocBrown I said it doesn't matter in this case. If I were to apply DRY, I would start by worrying why there are so many functions to start with. Without further context, I would pinpoint that as the architectural deficiency and tackle it. The problem at hand is only one of (probably) many of its symptoms and focusing on it can at best distract from the core issue. Principles can of course be used to turn trivialities into matters of principle, and while people just love to do that, I see principles as tools for devising simple solutions to complex problems.
    – back2dos
    Commented Nov 27, 2014 at 12:11
1

Of course there are pro and con effects; if there weren't, the community would long ago have figured them out, and everybody would agree to do always the one and never the other.

A switch statement is fine if the things you switch over have only one behaviour. A button does something when clicked, so that seems appropriate. But as soon as the variable you're switching over has more than one behaviour, you would need a second switch statement listing exactly the same cases. That's a violation of DRY, and it will get worse with every additional thing that's added to the class. And let's be honest: when was the last time you saw an established class get less complex?

An array of objects that all dispatch the same messages avoids this problem. It may or may not be less efficient than a switch compiled into a jump table. If it is, the difference may or may not be worth compromising other principles. If it is, it may or may not be a good idea if you do compromise them now, considering that the system will evolve further and today's small compromise might become a huge maintenance headache for years to come.

This is why only you know whether to choose one option over the other: because the particulars of your application probably outweigh the general pressures that we can enumerate for you.

(It's a bit like prejudice: when all you know about a web application is that it was written by volunteers in PHP, it's fine to assume that it's probably on the less secure side vs. one that is used by a major bank. After all, many such apps are in fact insecure. But if you have concrete examples of either web app, looking at the particulars of both instances is virtually always smarter than relying on general maxims, i.e. prejudice.)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.