Method Flags as Arguments vs Member Variables – Best Coding Practices

class-designcode-qualitycoding-stylemethodsvariables

I think the title "Method flags as arguments or as member variables?" may be suboptimal, but as I'm missing any better terminology atm., here goes:

I'm currently trying to get my head around the problem of whether flags for a given class (private) method should be passed as function arguments or via member variable and/or whether there is some pattern or name that covers this aspect and/or whether this hints at some other design problems.

By example (language could be C++, Java, C#, doesn't really matter IMHO):

class Thingamajig {
  private ResultType DoInternalStuff(FlagType calcSelect) {
    ResultType res;
    for (... some loop condition ...) {
      ...
      if (calcSelect == typeA) {
        ...
      } else if (calcSelect == typeX) {
        ...
      } else if ...
    }
    ...
    return res;
  }

  private void InteralStuffInvoker(FlagType calcSelect) {
    ...
    DoInternalStuff(calcSelect);
    ...
  }

  public void DoThisStuff() {
    ... some code ...
    InternalStuffInvoker(typeA);
    ... some more code ...
  }

  public ResultType DoThatStuff() {
    ... some code ...
    ResultType x = DoInternalStuff(typeX);
    ... some more code ... further process x ...
    return x;
  }
}

What we see above is that the method InternalStuffInvoker takes an argument that is not used inside this function at all but is only forwarded to the other private method DoInternalStuff. (Where DoInternalStuffwill be used privately at other places in this class, e.g. in the DoThatStuff (public) method.)

An alternative solution would be to add a member variable that carries this information:

class Thingamajig {
  private ResultType DoInternalStuff() {
    ResultType res;
    for (... some loop condition ...) {
      ...
      if (m_calcSelect == typeA) {
        ...
      } ...
    }
    ...
    return res;
  }

  private void InteralStuffInvoker() {
    ...
    DoInternalStuff();
    ...
  }

  public void DoThisStuff() {
    ... some code ...
    m_calcSelect = typeA;
    InternalStuffInvoker();
    ... some more code ...
  }

  public ResultType DoThatStuff() {
    ... some code ...
    m_calcSelect = typeX;
    ResultType x = DoInternalStuff();
    ... some more code ... further process x ...
    return x;
  }
}

Especially for deep call chains where the selector-flag for the inner method is selected outside, using a member variable can make the intermediate functions cleaner, as they don't need to carry a pass-through parameter.

On the other hand, this member variable isn't really representing any object state (as it's neither set nor available outside), but is really a hidden additional argument for the "inner" private method.

What are the pros and cons of each approach?

Best Answer

On the other hand, this member variable isn't really representing any object state (as it's neither set nor available outside), but is really a hidden additional argument for the "inner" private method.

That reinforces my gut feeling upon reading your question: try to keep this data as local as possible, i.e. don't add it to the object state. This reduces the state space of your class, making your code simpler to understand, test and maintain. Not to mention that avoiding shared state makes your class more threadsafe too - this may or may not be a concern to you right now, but it may make a huge difference in the future.

Of course, if you need to pass around such flags excessively, it may become a nuisance. In this case, you may consider

  • creating parameter objects to group related parameters together into a single object, and/or
  • encapsulating this state and the associated logic into a separate family of strategies. The viability of this depends on the language: in Java, you need to define a distinct interface and a (possibly anonymous) implementation class per each strategy, whereas in C++ or C# you may use function pointers, delegates or lambdas, which simplifies the code considerably.
Related Topic