Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm writing classes that "must be used in a specific way" (I guess all classes must...).

For example, I create the fooManager class, which requires a call to, say, Initialize(string,string). And, to push the example a little further, the class would be useless if we don't listen to it's ThisHappened action.

My point is, the class I'm writing requires method calls. But it will compile just fine if you don't call those methods and will end up with an empty new FooManager. At some point, it will either not work, or maybe crash, depending on the class and what it does. The programmer that implements my class would obviously look inside it and realize "Oh, I didn't call Initialize!", and it'd be fine.

But I don't like that. What I would ideally want is the code to NOT compile if the method wasn't called; I'm guessing that's simply not possible. Or something that would immediately be visible and clear.

I find myself troubled by the current approach I have here, which is the following:

Add a private boolean value in the class, and check everywhere necessary if the class is initialized ; if not, I will throw an exception saying "The class wasn't initialized, are you sure you're calling .Initialize(string,string)?".

I'm kind of okay with that approach, but it leads to a lot of code that is compiled and, in the end, not necessary to the end user.

Also, it's sometimes even more code when there are more methods than just an Initiliaze to call. I try to keep my classes with not too many public methods/actions, but that's not solving the problem, just keeping it reasonable.

What I'm looking for here is:

  • Is my approach correct?
  • Is there a better one?
  • What do you guys do/advise?
  • Am I trying to solve a non-issue? I've been told by colleagues it's the programmer's to check the class before trying to use it. I respectfully disagree, but that's another matter I believe.

EDIT : About the possible duplicate of this question : those questions are entirely different. I'm not considering wether or not I should call 1 big method vs many small ones. I'm asking for a way to make sure that method is called at all. Wether it's a small Init()or many calls is irrelevant.

Put it simply, I'm trying to figure out a way to never forget to implement calls when that class is reused later, or by someone else.

share|improve this question
5  
Ensuring that calls to the methods of a class occur in a specific order is not possible in general. This is one of many, many problems that are equivalent to the halting problem. Although it would be possible to make non-compliance a compile-time error in some cases, there is no general solution. That is presumably why few languages support constructs that would let you take diagnose at least the obvious cases, even though data-flow analysis has become quite sophisticated. – Kilian Foth yesterday
3  
4  
The answer to the other question is irrelevant, the question is not the same, therefore they are different questions. If someone looks for that discussion he wouldn't type the title of the other question. – Zil yesterday
4  
What's preventing to merge the content of initialize in the ctor ? Must the call to initialize be made late after the object creation ? Would the ctor be too "risky" in the sense it could throw exceptions and break the creation chain ? – Spotted yesterday
4  
This problem is called temporal coupling. If you can, try to avoid putting the object in an invalid state by throwing exceptions in the constructor when encountering invalid inputs, that way you'll never get past the call to new if the object isn't ready to be used. Relying on an initialization method is bound to come back to haunt you and should be avoided unless absolutely necessary, at least that's my experience. – Seralize 14 hours ago

In such cases, it is best to use the type system of your language to help you with proper initialization. How can we prevent a FooManager from being used without being initialized? By preventing a FooManager from being created without the necessary information to properly initialize it. In particular, all initialization is the responsibility of the constructor. You should never let your constructor create an object in an illegal state.

But callers need to construct a FooManager before they can initialize it, e.g. because the FooManager is passed around as a dependency.

Don't create a FooManager if you don't have one. What you can do instead is pass an object around that lets you retrieve a fully constructed FooManager, but only with the initialization information. (In functional-programming speak, I'm suggesting you use partial application for the constructor.) E.g.:

ctorArgs = ...;
getFooManager = (initInfo) -> new FooManager(ctorArgs, initInfo);
...
getFooManager(myInitInfo).fooMethod();

The problem with this is that you have to supply the init info every time you access the FooManager.

If it's necessary in your language, you can wrap the getFooManager() operation in a factory-like or builder-like class.

I really want to do runtime checks that the initialize() method was called, rather than using a type-system-level solution.

It is possible to find a compromise. We create a wrapper class MaybeInitializedFooManager that has a get() method that returns the FooManager, but throws if the FooManager wasn't fully initialized. This only works if the initialization is done through the wrapper, or if there is a FooManager#isInitialized() method.

class MaybeInitializedFooManager {
  private final FooManager fooManager;

  public MaybeInitializedFooManager(CtorArgs ctorArgs) {
    fooManager = new FooManager(ctorArgs);
  }

  public FooManager initialize(InitArgs initArgs) {
    fooManager.initialize(initArgs);
    return fooManager;
  }

  public FooManager get() {
    if (fooManager.isInitialized()) return fooManager;
    throw ...;
  }
}

I don't want to change the API of my class.

In that case, you'll want to avoid the if (!initialized) throw; conditionals in each and every method. Fortunately, there is a simple pattern to solve this.

The object you provide to users is just an empty shell that delegates all calls to an implementation object. By default, the implementation object throws an error for each method that it wasn't initialized. However, the initialize() method replaces the implementation object with a fully-constructed object.

class FooManager {
  private CtorArgs ctorArgs;
  private Impl impl;

  public FooManager(CtorArgs ctorArgs) {
    this.ctorArgs = ctorArgs;
    this.impl = new UninitializedImpl();
  }

  public void initialize(InitArgs initArgs) {
    impl = new MainImpl(ctorArgs, initArgs);
  }

  public X foo() { return impl.foo(); }
  public Y bar() { return impl.bar(); }
}

interface Impl {
  X foo();
  Y bar();
}

class UninitializedImpl implements Impl {
  public X foo() { throw ...; }
  public Y bar() { throw ...; }
}

class MainImpl implements Impl {
  public MainImpl(CtorArgs c, InitArgs i);
  public X foo() { ... }
  public Y bar() { ... }
}

This extracts the main behaviour of the class into the MainImpl.

share|improve this answer
4  
I like the first two solutions (+1), but I don't think your last snippet with its repetition of the methods in FooManager and in UninitialisedImpl is any better than repeating if (!initialized) throw;. – Bergi 20 hours ago
1  
@Bergi Some people love classes too much. Although if FooManager has a lot of methods, it might be easier than potentially forgetting some of the if (!initialized) checks. But in that case you should probably prefer to break up the class. – immibis 19 hours ago
1  
A MaybeInitializedFoo doesn't seem better than an initialized Foo too me, but +1 for giving some options/ideas. – Matthew James Briggs 17 hours ago
4  
+1 The factory is the correct option. You can't improve the a design without changing it, so IMHO the last bit of the answer about how to half are it is not going to help the OP. – Nathan Cooper 12 hours ago
1  
@Bergi I have found the technique presented in the last section to be tremendously useful (see also the “Replace conditionals through Polymorphism ” refactoring technique, and the State Pattern). It is easy to forget the check in one method if we use an if/else, it's much harder to forget implementing a method required by the interface. Most importantly, the MainImpl corresponds exactly to an object where the initialize method is merges with the constructor. This means the implementation of MainImpl can enjoy the stronger guarantees this affords, which simplifies the main code. … – amon 12 hours ago

The most effective and helpful way to prevent clients from "misusing" an object is by making it impossible.

The simplest solution is to merge Initialize with the constructor. That way the object will never be available for the client in the the uninitialized object so the error is not possible.

If you for some reason need to be able to access the uninitialized object before initialization, then you could have the two states implemented as separate classes, so you start out with an UnitializedFooManager instance, which have an Initialize(...) method which returns InitializedFooManager. The methods which can only be called in the initialized state only exist on InitializedFooManager. This approach can be extended to multiple states if you need to.

Compared to runtime exceptions, it is more work to represent states as distinct classes, but it also give you compile-time guarantees that you are not calling methods which are invalid for the object state, and it documents the state transitions more clearly in code.

share|improve this answer
2  
Also I remember cases where it was simply not possible to go from the constructor, but I don't have an example to show right now – Zil yesterday
1  
The example now describes a factory pattern - but the first sentence actually describes RAII paradigm. So which one is this answer supposed to recommend? – Ext3h yesterday
8  
@Ext3h I don't think the factory pattern and RAII are mutually exclusive. – Pieter B yesterday
    
@PieterB No, they are not, a factory may ensure RAII. But only with the additional implication that the template/constructor args (called UnitializedFooManager) must not share a state with the instances (InitializedFooManager), as Initialize(...) has actually Instantiate(...) semantic. Otherwise, this example leads to new problems if the same template is used twice by a developer. And that's not possible to prevent/validate statically either if the language doesn't explicitly support move semantics in order to reliably consume the template. – Ext3h yesterday
2  
@Ext3h: I recommend the first solution since it is the simplest. But if the client need to be able to access the object before calling Initialize, then you can't use it, but you might be able to use the second solution. – JacquesB yesterday

I would normally just check for intiialisation and throw (say) an IllegalStateException if you try and use it whilst not initialised.

However, if you want to be compile-time safe (and that seems laudable), why not treat the initialisation as a factory method returning a constructed and initialised object e.g.

ComponentBuilder builder = new ComponentBuilder();
Component forClients = builder.initialise(); // the 'Component' is what you give your clients

and so you control the objects creation and lifecycle, and your clients get the Component as a result of your initialisation. It's effectively a lazy instantiation.

share|improve this answer
    
Good answer -- 2 good options in a nice succinct answer. Other answers above present type-system gymnastics which are (theoretically) valid; but for the majority of cases, these 2 simpler options are the ideal practical choices. – Thomas W 16 hours ago

I'm going to break a little bit from the other answers and disagree: it's impossible to answer this without knowing what language you're working in. Whether or not this is a worthwhile plan, and the right sort of "warning" to give your users depends entirely on the mechanisms that your language provides and the conventions other developers of that language tend to follow.

If you have a FooManager in Haskell, it would be criminal to allow your users to build one that isn't capable of managing Foos, because the type system makes it so easy and those are the conventions that Haskell developers expect.

On the other hand, if you're writing C, your coworkers would be entirely within their rights to take you out back and shoot you for defining separate struct FooManager and struct UninitializedFooManager types that support different operations, because it would lead to unnecessarily complex code for very little benefit.

If you're writing Python, there's no mechanism in the language to let you do this.

You are probably not writing Haskell, Python, or C, but they're illustrative examples in terms of how much/how little work the type system is expected and able to do to do.

Follow the reasonable expectations of a developer in your language, and resist the urge to over-engineer a solution that does not have a natural, idiomatic implementation (unless the mistake is so easy to make and so hard to catch that it's worth going to extreme lengths to make it impossible). If you don't have enough experience in your language to judge what's reasonable, follow the advice of someone who knows it better than you.

share|improve this answer
    
I'm a little confused by "If you're writing Python, there's no mechanism in the language to let you do this." Python has constructors, and it's pretty trivial to create factory methods. So maybe I don't understand what you mean by "this"? – A. L. Flanagan 2 hours ago
    
By "this," I meant a compile-time error, as opposed to a runtime one. – Patrick Collins 1 hour ago

When I implement a base class that requires extra initialisation information or links to other objects before it becomes useful, I tend to make that base class abstract, then define several abstract methods in that class that are used in the flow of the base class (like abstract Collection<Information> get_extra_information(args); and abstract Collection<OtherObjects> get_other_objects(args); which by contract of inheritance must be implemented by the concrete class, forcing the user of that base class to supply all the things required by the base class.

Thus when I implement the base class, I immediately and explicitly know what I have to write to make the base class behave correctly, since I just need to implement the abstract methods and that's it.

EDIT: to clarify, this is almost the same as providing arguments to the constructor of the base class, but the abstract method implementations allow the implementation to process the arguments passed to the abstract method calls. Or even in the case of no arguments being used, it can still be useful if the return value of the abstract method depended on a state that you can define in the method body, which isn't possible when passing the variable as an argument to the constructor. Granted you can still pass an argument that will have dynamic behaviour based on the same principle if you'd rather use composition over inheritance.

share|improve this answer

As you seem to not want to ship the code check to the customer (but seem fine to do it for the programmer) you could use assert functions, if they are available in your programming language.

That way you have the checks in the development environment (and any tests a fellow dev would call WILL fail predictably), but you will not ship the code to the customer as asserts (at least in Java) are only selectively compiled.

So, a Java class using this would look like this:

/** For some reason, you have to call init and connect before the manager works. */
public class FooManager {
   private int state = 0;

   public FooManager () {
   }

   public synchronized void init() {
      assert state==0 : "you called init twice.";
      // do something
      state = 1;
   }

   public synchronized void connect() {
      assert state==1 : "you called connect before init, or connect twice.";
      // do something
      state = 2;
   }

   public void someWork() {
      assert state==2 : "You did not properly init FooManager. You need to call init and connect first.";
      // do the actual work.
   }
}

Assertions are a great tool to check for runtime state of your program that you require, but don't actually expect to anyone ever doing wrong in a real environment.

Also they are quite slim and don't take up huge portions of if() throw... syntax, they don't need to be caught, etc.

share|improve this answer

The way I've solved this problem before was with a private constructor and a static MakeFooManager() method within the class. Example:

public class FooManager
{
     public string Foo { get; private set; }
     public string Bar { get; private set; }

     private FooManager(string foo, string bar)
     {
         Foo = foo;
         Bar = bar;
     }

     public static FooManager MakeFooManager(string foo, string bar)
     {
         // Can do other checks here too.
         if(foo == null || bar == null)
         {
             return null;
         }
         else
         {
             return new FooManager(foo, bar);
         }
     }
}

Since a constructor is implemented, there is no way for anyone to create an instance of FooManager without going through MakeFooManager().

share|improve this answer
1  
this seems to merely repeat point made and explained in a prior answer that was posted several hours before – gnat 15 hours ago
    
does this have any advantage at all over simply null-checking in the ctor? it seems like you just made a method that does nothing but wrapping another method. why? – kai 9 hours ago
    
Also, why are foo and bar member variables? – Patrick M 11 mins ago

protected by gnat 7 hours ago

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

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