3

I'm in the middle of refactoring a project (in C++11) and I'm struggling with a decision is it good to change huge enum with about 100 record to separate classes. This enum is used in about 4 places in code in 4 different functions with huge switch statements. For every enum, the record is some code in every function.

I'm thinking about creating an interface and them implement in classes but the number of classes in the project will increase by 100. That's why I'm concerned if this will cost me some performance decrease or will have a huge impact on memory usage or will have other consequences. I know that code will be in better condition but also it's very important that it will work fast (not extremely fast) but it's server application so it's an important factor.

Some code samples:

enum MyEnum {
  RECORD_1,
  RECORD_2,
  ...
  RECORD_100
}

void doSomething(MyEnum en) {
  switch (en) {
  case RECORD_1: {

  } break;
  case RECORD_2: {

  } break;
  //...
  case RECORD_100: {

  } break;
  };
}

void doSomethingElse(MyEnum en) {
  switch (en) {
  case RECORD_1: {

  } break;
  case RECORD_2: {

  } break;
  //...
  case RECORD_100: {

  } break;
  };
}

So I'm thinking in creating interface:

class AbstractInterface {
public:
  virtual void doSomething() = 0;
  virtual void doSomethingElse() = 0;
};

And then implemets this interface in classes:

class Record1 : public AbstractInterface {
public:
  void doSomething() override;
  void doSomethingElse() override;
};

//...

class Record2 : public AbstractInterface {
public:
  void doSomething() override;
  void doSomethingElse() override;
};

Is it a good way of refactoring this type of code in that way? and not decreasing the performance of the application?

Chen Li
  • 123
  • 4
Piter _OS
  • 91
  • 1
  • 1
  • 6
  • 3
    Not really. Even if there's any, it's going to be minuscule and you shouldn't worry about it. – Andy Apr 18 '18 at 08:19
  • 1
    Possible duplicate of [Is micro-optimisation important when coding?](https://softwareengineering.stackexchange.com/questions/99445/is-micro-optimisation-important-when-coding) – gnat Apr 18 '18 at 08:22
  • @DavidPacker So in your opinion is it worth doing that refactoring and and i won't spot huge impact on apllication performance? – Piter _OS Apr 18 '18 at 08:34
  • Have you measured how long *taking the branch* in the switch compares to the body of the case statements? – Caleth Apr 18 '18 at 08:59
  • @Caleth Can you clarify what you mean "how long taking the branch in switch statement comapres to the cody od case" ? – Piter _OS Apr 18 '18 at 09:39
  • You are worried about replacing a switch with a virtual message dispatch. If one takes 0.0001% and the other 0.00001% of the time required to *do whatever*, does *how long the dispatch takes* matter? – Caleth Apr 18 '18 at 09:42
  • 1
    Bottom line: It is slower, but it's negligible. You should refactor because 100+ switch statement is awful, not because doing it that way is faster. The way you mentioned is only recommended if every 100 of these has its *own* way of doing it. Otherwise, reuse when possible (use a dictionary that maps each 100 with the instance that does the job, if necessary). – Neil Apr 18 '18 at 10:03

2 Answers2

8

There is not going to be a huge change in performance. Your current solution uses a large switch/case for dispatch, your proposed solution uses dynamic dispatch. Both imply some indirection and/or branching. Both are essentially the same code.

There are a couple of tiny differences that would point to the switch being slightly faster:

  • Enums are typically backed by ints, but your objects will probably be a pointer to the object + one vtable pointer inside the object. So per instance you might have a 4× higher memory use, plus additional pointer indirection. Is this relevant? Likely not, unless you are storing many millions of instances at once.

  • The code for the different branches in the switch are right next to each other, which might be good for caching. In contrast, the objects, vtables, and method bodies for your objects might be all over the place. When calling a rarely-used method, the processor will have to wait until the data is loaded into the cache. OTOH the switch might be so large that it's never fully loaded into the cache either, so the same drawbacks may apply there.

There certainly are scenarios where cache-friendly programming makes a huge difference. For the majority of code, that's not the case. I'd like to point out that many languages such as Java or Python have fundamental inefficiencies in their object model, yet still deliver acceptable performance in many applications.

amon
  • 132,749
  • 27
  • 279
  • 375
  • 1
    We don't know the solution will use dynamic dispatch. It may be resolved statically, or semi statically (via prediction). – Frank Hileman Apr 19 '18 at 01:02
2

I'm thinking about creating an interface and them implement in classes but the number of classes in project will increase by 100.

Don't worry about it.

Even a basic, "Hello World", program probably uses [at least] that many classes from the .Net Framework.

Your 100 classes each of which "does its own thing" is going to be far more maintainable in the long term than your current, four methods that have to "know all about 100 different classes".

Phill W.
  • 11,891
  • 4
  • 21
  • 36