Pergunta

Is there any purpose for declaring an init() method for a type?

I'm not asking whether we should prefer init() over a constructor or how to avoid declaring init().

I'm asking if there is any rationale behind declaring an init() method (seeing how common it is) or if it's a code smell and should be avoided.


The init() idiom is quite common, but I have yet to see any real benefit.

I'm talking about types that encourage initialization via a method:

class Demo {
    public void init() {
        //...
    }
}

When will this ever be of use in production code?


I feel it may be a code smell since it suggests the constructor does not fully initialize the object, resulting in a partially created object. The object should not exist if it's state isn't set.

This makes me believe it may be part of some kind of technique used to speed up production, in the sense of enterprise applications. It is the only logical reason I can think of having such an idiom, I'm just not sure how it would be beneficial if so.

Foi útil?

Solução

Yes, it's a code smell. A code smell isn't something that necessarily always needs to get removed. It's something that makes you take a second look.

Here you have an object in two fundamentally different states: pre-init and post-init. Those states have different responsibilities, different methods that are allowed to be called, and different behavior. It's effectively two different classes.

If you physically make them two separate classes you will statically remove a whole class of potential bugs, at the cost of maybe making your model not match the "real world model" quite as closely. You usually name the first one Config or Setup or something like that.

So next time, try refactoring your construct-init idioms into two-class models and see how it turns out for you.

Outras dicas

It depends.

An init method is a code smell when it is not necessary to have the object initialization separated from the constructor. There are sometimes cases where it makes sense to separate these steps.

A quick Google search got me this example. I can easily imagine more cases where the code executed during object allocation (the constructor) might better be separated from the initialization itself. Maybe you have a leveled system, and allocation/construction takes place in level X, but initialization only in level Y, because only Y can provide the necessary parameters. Maybe the "init" is costly and must be run only for a subset of the allocated objects, and the determination of that subset can only be done in level Y. Or you want to override the (virtual) "init" method in a derived class which cannot be done with a constructor. Maybe level X provides you with allocated objects from an inheritance tree, but level Y is not aware of the concrete derivation, only about the common interface (where init maybe defined).

Of course, to my experience these cases are only a small percentage of the standard case where all initialization can be done directly in the constructor, and whenever you see a separate init method, it might be a good idea to question its necessity.

My experience breaks down into two groups:

  1. Code where init() is actually required. This can occur when a superclass or framework prevents your class's constructor from getting all its dependencies during construction.
  2. Code where init() is used but could have been avoided.

In my personal experience I have seen just a few instances of (1) but many more instances of (2). Consequently, I usually assume an init() is a code-smell, but this isn't always the case. Sometimes you just can't get around it.

I have found using the Builder Pattern can often help remove the need/desire to have a init().

A typical scenario when an Init method comes in handy is when you have a configuration file that you want to change and to have the change taken into account without restarting the application. This, of course, does not mean that an Init method must be called separately from a constructor. You could call an Init method from a constructor, and then call it later when/if the configuration parameters change.

To sum up: as for most dilemmas out there, whether this is a code smell or not, depends on the situation and the circumstances.

Depends on how you use them.

I use that pattern in garbage collected languages like Java/C# when I don't want to keep reallocating an object on the heap (like when I'm making a video game and need to keep performance high, garbage collectors kill performance). I use the constructor to make other heap allocations it needs, and init to create the basic useful state right before every time I want to reuse it. This is related to the concept of object pools.

It is also useful if you have several constructors that share a common subset of initialization instructions, but in that case init will be private. That way I can minimize each constructor as much as possible, so each one only contains its unique instructions and a single call to init to do the rest.

In general though, it is a code smell.

init() methods can make quite some sense when you have objects that need external resources (like, for example, a network connection) that are concurrently used by other objects. You might not want/need to hog the resource for the lifetime of the object. In such situations, you might not want to allocate the resource in the constructor when the resource allocation is likely to fail.

Especially in embedded programming, you want to have a deterministic memory footprint, so it is common (good?) practice to call your constructors early, maybe even static, and only initialize later when certain conditions are met.

Other than such cases I think everything should go into a constructor.

Generally I prefer a constructor which receives all the arguments required for a functional instance. That makes clear all the dependencies of that object.

On the other hand, I use a simple configuration framework which requires a parameter-less public constructor, and interfaces for injecting dependencies and configuration values. After that is done, the configuration framework calls the init method of the object: now you received all the things I have for you, do the last steps to get ready for work. But note: it is the configuration framework which automatically calls the init method, such you won't forget to call it.

There is no code smell if the init()-method is semantically embedded in the state-lifecycle of the object.

If you need to call init() to put the object into a consistent state it is a code smell.

There are several technical reasons that such a structure exists:

  1. framework hook
  2. resetting the object to initial state (avoid redundancy)
  3. possibility to override during tests

The name init may sometimes be opaque. Let's take a car and an engine. To start the car (only power up, to listen to the radio) you want to verify that all systems are ready to go.

So you construct an engine, a door, a wheel etc. your screen shows engine = off.

No need to start monitoring the engine etc. as those are all expensive. Then when you turn the key to ignite you call engine-> start. It starts running all expensive processes.

Now you see engine = on. And the process for ignition starts.

The car won't power up without the engine being available.

You can replace engine with your complex calculation. Like an Excel cell. Not all cells need to be active with all event handlers all the time. When you focus on a cell you can start it. Increasing performance that way.

Licenciado em: CC-BY-SA com atribuição
scroll top