5

The internal framework my company uses has a pretty pivotal Object that has a pattern of being instantiated as a member of a class with a no argument constructor but to be usable you have to call a start method. I understand that constructors are generally minimalist but at the same time why be able to construct an unusable object that you just have to call start on anyway?

Basically this

public class Someclass{
    FrameworkThingy thingy = new FrameworkThingy();

    //Framework auto runs this method as part of Spring beans
    public void startUpMethod() {
        thingy.start();
        // Why not just do the start stuff in the constructor?
    }
}

5 Answers5

10

When I've seen this pattern in the past it's always been for one of the following reasons:

  1. Starting the class is an expensive operation. Leaving the starting logic in the constructor would slow down application bootstrapping/startup.
  2. Timing concerns. It could be that your class should never be started before another event in your application. So, instead of leaving the responsibility to Start to the class itself it may make more sense to hand that responsibility to a timing coordinator class.
  3. Stopping and Restarting are legitimate operations as well and only ever invoked explicitly. In this case, making Start be invoked implicitly in the constructor breaks the pattern and makes the class semantics a bit confusing.

Without any more specifics about your situation I can't really give you a more specific answer.

MetaFight
  • 11,619
3

Like many questions in software development, the answer again is "it depends".

Some of the articles other questions linked in answers to this advocate for 'lightweight' constructors that avoid doing any 'real work'. However, there are many circumstances where it is appropriate to initialize and begin doing work in the constructor.

Usually, it's appropriate when instantiation is cheap, when instantiating has essentially one conceptual successful outcome, and where there is nothing valid or meaningful to do between construction and a hypothetical start.

To start, let's characterize the idea of a Start() method is. In many situations it would instead be called Init() or Open() or similar. It would likely encompass stuff like opening or creating files, opening network ports or connections, connecting to a database, accessing hardware, starting new threads, etc. What are some situations where it would make sense to create an object and start performing those operations right away?

Take the example of something that deals with files on the file system. If we take the position that we should do minimal work in the constructor, then a typical usage is we instantiate our filewriter class, then later call Open() or similar, then later start providing data in some way. Since we want our object to be in a valid state at all times, we should verify we can access the file upon instantiation. If the file can't be accessed, we have to throw an exception upon construction. If everything is good to go, we can later call Open() and get to work. But wait, life is never that simple. We've created a race condition, as it's possible that between instantiation and Open(), the file has become inaccessible. So, we'd need to encase Open() in another try/catch to handle that scenario. How is that better that instantiating and opening in one operation? I'd argue that in this scenario the additional method is worse than doing the work in the constructor.

Even more complex instantiation procedures can be performed with paradigm in an easy to debug and test way, and dependency injection is often the means to do that. A database interface being provided an instantiated DatabaseConnection is a common example you may have seen in the wild. Instantiated, valid objects are progressively injected into objects using them, guaranteeing a valid state along the way.

Some comments and answers have stated that sometimes, you want to instantiate your object and later have it start doing its work, which to me makes little sense for cheap objects. It's pretty commonly stated to declare your variables as close to as when you're going to use them, why would that rule be different with objects? And if you do have them separate, what value are you providing yourself by keeping them separate? If you are opening a network port, at the moment you're ready, you have all the information you need to do so, so what real difference is there between a class that makes you call an additional method?

By doing the Start() work in the constructor, you are able to ensure that there is a single way to use a class, for that single way to be the right way, and for the compiler to enforce it for you. Having separate start methods, you have temporal coupling that trades off compile time programming errors for runtime errors. In a way, starting up in the constructor let's you reap some of the conceptual benefits of immutable objects, but for objects that do things.

Now, like I said, sometimes the answer is yes, sometimes it's no. Sometimes it does make sense to have an exposed Start() method. Sometimes you're interfacing with some other system where the RAII and OOP and similar paradigms don't exist, and there aren't exceptions, etc, and you have no choice. Sometimes instantiating is really expensive. In those cases and others it makes sense to have separate start methods. Only you can decide what's appropriate.

whatsisname
  • 27,703
2

Because that's not what constructors are for. Constructors are for constructing. I don't expect or want objects to do anything other than get ready to be used when I construct them. If they start doing something I didn't ask them to do you're surprising me, the object user.

Separating use from construction is hard enough without dealing with objects that refuse to exist unless they can do something first. A constructor should get the object into a useable state. That's all. Any more is clutter.

candied_orange
  • 119,268
2

Because Misko says you should avoid doing work in the constructor.

You are forcing me to think like you

You can't tell the future. I know this because I can't. How is your object going to be used? Can you assume it will be used that way, every single time? Maybe someone finds a use for it later on down the road that you hadn't imagined, but is practical. And it also requires that you do not call the start method. Since you moved that logic into the constructor they're just out of luck and an opportunity for code reuse is lost. Because you wanted to call a start method in the constructor.

Can I trust a new instance of your object?

The only constant in software development is that things change. I want a new instance of your object, and I want it right now. But you call a start method in the constructor. Then someone comes along and adds some more functionality into the start method, and now the instance that I wanted is completely different, even though no new dependencies have been introduced. I didn't change any of my code, but now it doesn't work and it's all your fault. Because you wanted to call a start method in the constructor.

I'm a programmer and that means I'm lazy

I have 28 things to do at work today. I know that I have to go to that meeting a 2:00pm. The meeting room is around the corner and down the hall, so I think I'll get there on time if I leave my desk at 1:58pm. I know that if I leave any earlier I will just be sitting there twiddling my thumbs while I wait for other people to get there. This is inefficient, which is the main reason for my laziness. Even if I'm just browsing programmers.stackexchange.com between 1:52pm and 1:58pm, that's a much better use of my time than just sitting in a conference room counting ceiling tiles. Besides, I may get an e-mail at 1:57pm saying that the meeting's cancelled, but if I left my desk at 1:55pm I wouldn't get it, and it would probably be around 2:05pm before I started getting a little anxious that I was the only one around, meaning that, because I wanted to be an eager go-getter, I actually wound up wasting an extra 10 whole minutes counting ceiling tiles. That's exactly what happened last time. There's not that many of them, so I counted them twice, just to be sure I was right (I was).

The point of this is that, although I need a new instance of your object now, I would much prefer it if you would just let me start the darn thing only when I'm good and ready and sure that I want it to actually start. If you automatically call start in the constructor, you are forcing me to construct that object at a particular point in time when you want me to. What if I want to construct it earlier for some reason, but at that point I'm just not quite ready to start? I can't, because you wanted to call a start method in the constructor.

Testing

This I think is the biggest reason. You need to mock an object to test against, but the internals of that object are modified (work is done) during the construction phase. With just a mock object, however, that code doesn't get a chance to run so you must not only mock that object whenever you need to test something that uses it, but also modify the mock object in the same manner as your start method every single time. Oh, Joe updated the start method, so now that means I have 57 tests I need to update before the build will pass. This is buredensome and will probably result in no tests being written on anything that relies on the object with the heavy constructor.

Because you wanted to call a start method in the constructor.

1

TL;DR

In mobile apps, certain objects are created once, but started multiple times - so the placement of code needs to be done carefully to avoid various unwanted effects leading to bad UX.


Having some experience with mobile development, I encounter on a daily basis situations1 where certain objects need to go through a set of initialization, or lifecycle methods before they are truly usable.

To a person making their first app, it might seem completely unnecessary to separate onCreate() from onStart(), and perhaps even from onResume(). Why is this? Probably because the envisioned use case is something like a calculator on your desktop - "open the app, do the things you need, click the big exit button, restart the app at a later time if needed again". Surely, this can work well in some cases, but what happens when you need to take a call while working with the app, or god forbid, try to upload a photo?

If you, the beginner, decided to put everything in onCreate(), when the app is resumed it might be unresponsive or have some unexpected state (paused animations?). If you put everything into onResume(), you might run into some memory leaks because you will end up instantiating objects more than once.

On platforms with relatively limited resources, the developer needs to be very mindful of how and when to use them, because every choice boils down to user experience - is the app responsive? Does it consume a lot of power? Does it require the user to repeat the same actions over and over again?

To conclude: splitting initialization code into several stages (or methods) may improve performance (or at the very least the appearance of performance; by not having to run code a needless amount of times) and overall user experience.


1 - The clearest examples of this are the Android Activitysummary or the iOS UIViewController.

Dev-iL
  • 233