Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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?

share|improve this question

closed as too broad by GlenH7, ChrisF Dec 5 '14 at 12:52

There are either too many possible answers, or good answers would be too long for this format. Please add details to narrow the answer set or to isolate an issue that can be answered in a few paragraphs. If this question can be reworded to fit the rules in the help center, please edit the question.

    
recommended reading: What is the problem with “Pros and Cons”? –  gnat Nov 27 '14 at 9:36
    
Reminds of a classic refactoring: codereview.stackexchange.com/questions/9934/… –  Den Nov 27 '14 at 9:50

3 Answers 3

up vote 2 down vote accepted

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, thre, 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 neglectable. And when it is not, you will have to try and measure if a replacement by a switch statement does really bring the necessary performance gain.

share|improve this answer
    
Great Scott!!! you are right :P –  John Demetriou Nov 27 '14 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 Nov 27 '14 at 11:55

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.

share|improve this answer
    
Violating the DRY principle does not matter? Sorry, but I heavily disagree. –  Doc Brown Nov 27 '14 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 Nov 27 '14 at 12:11

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.)

share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.