0

In dynamically and weakly-typed languages*, I often find myself with structures like the following pseudocode:

class Stateful:

    # [ various datamembers / attributes / properties / fields / etc. ]

    define constructor(arguments):
        configureA(arguments)
        # [ maybe set a variable or two here ]
        configureB()

    define configureA():
    ## configures the most important parts of Stateful state
    ## throws some exceptions if these basic changes cannot be made
        # [ code goes here ]

    define configureB():
    ## handles a little bit of bookkeeping. Usually called after configureA().
    ## expects the following variables to be set: <list of vars>
        # [ code goes here ]
    #
    # ...

Though there may be a better way to do this such as providing a single block that describes the call-sequence and notes consequences all in once place, is it a good idea in general to document expected call-sequences? If it is a good idea to "just document" this sort of thing when it comes up, are there established best-practices? Or is doing so perhaps a sign of a deeper problem?

* Answers to this question suggest that configureA() return a type which is required by configureB(), then have configureB() return a type which is required by configureC(), etc. I'm asking here about languages which are weakly and/or dynamically typed, or in instances wherein adding extra classes for each configuration-step would just yield a bunch of smallish classes with low to no reusability and poor maintainability given a need for even more classes if config gains steps.

My mixed thoughts about this follow below the line:


Reasons to document expected call-sequences (in some form or other):

  • Such comments often help me track down would-be mysterious errors in my code, by leading me to re-examine call-sequences after periods of being focused on other implementation-details.

  • If code for stateful classes needs to be updated, this should help other programmers avoid such mysterious errors as well.

  • Especially for private functions, describing functions' "contracts" in comments allows me to focus on essential functionality in and less on throw new DescriptiveErrorMessage("Let's talk for a while, shall me? ..."). Even in the case where exceptions should ultimately be thrown, I find it easier to go back and examine exception-cases after I've been apart from the real "working" part of the code for a while.

  • Not other all programmers will be using IDEs capable of generating information about standing call-sequences for them, and even if they did, an IDE may not be able to tell a programmer whether a certain sequence of initialization-calls is necessary or just a de-facto "it's in that order because that's how it was written"

Reasons not to do this:

  • Comments like these are implementation-specific and may not have a lot of usefulness after a class is stabilized.

  • Comments like these increase code's maintenance-burden because they need to be kept up-to-date in addition to the code itself.

  • The code should speak for itself and good programmers should use introspection instead of reading my drivel.

  • Comments specifying these kinds of sequential preconditions may just be a crutch for bad code.

3
  • 2
    Please note that while the duplicate question is different, its accepted answer will address the core concerns in your question.
    – user22815
    Oct 22, 2015 at 2:42
  • 1
    @Snowman What if somebody wants to leave an answer to this question which wouldn't be appropriate as an answer to the other question? Oct 22, 2015 at 12:03
  • 1
    @BenAaronson then the other question would not be a duplicate of this one.
    – user22815
    Oct 22, 2015 at 13:34

1 Answer 1

1

Consider the following "what-if" thought exercise:

Suppose you modify configureA and configureB, so that instead of actually doing the work that is order dependent, the two methods merely save a copy of the parameters that were passed in.

Then, write another method, realConfigureA_and_B which takes those saved parameters, and do the actual work that is order dependent.

The question to ask is: if you split the functions this way, will the clients of this class fail? Will the clients need to do things with this class while the class has already configured A but not B (being in a state of partially initialized)?

If the clients don't actually care, then it might be the case that the order dependency could be removed in some way by rearranging code, or by merging code from some functions into a single function.

If the clients can't tolerate this, then in other programming languages it would be a sign that the class is doing too much work, and needs to be split up into several classes.


Other options. In some other programming paradigms, ...

The class may require the clients to provide already-initialized instances of A and B, instead of doing it inside the class.

The class may implement lazy-initialization for A and B, that is, it postpones the initialization until it cannot do that anymore, then it will initialize what is needed.

The class may require its clients to provide some callbacks, whose job is to help initialize those things. The class is in control of the order of initialization, and the clients are required to follow the class's choice of ordering, and to provide the initialization info upon request.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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