Calling Setters from a Constructor

calling setters from a constructor

Personally, I would set the variable directly in most cases.

Methods usually expect that the instance is fully-formed by the time they're called. In particular, calling an overridden method from a constructor is a recipe for hard-to-understand code and hard-to-spot bugs.

Having said that, I often try to make classes immutable anyway, in which case not only is there no setter, but you have to set the final variable from the constructor (or a variable initializer) anyway :)

Where properties have logic, setter logic is usually validation and sometimes change propagation to observers. I'd usually expect the constructor parameters to be checked explicitly at the start of the method, and you wouldn't want any change propagation to occur before an instance is fully created anyway.

Should I use getters and setters in constructors?

You should not call getters and setters from the constructor.

A constructor constructs the specific class in which it is defined. It is its job to initialise the fields because - well - nothing else will.

The only way to guarantee initialising the fields is to assign them. If you call a setter there is a chance it could be overridden and it might do something else. It might call a method in a sub-class which is not initialised yet.

Calling a getter is also a bad idea if you are just getting a field from the same class. If it has been declared in the super-class you might justify it; if you need to get data from the super-class in the sub-class, you will have to call the getter (unless it is protected). If you need to communicate data from a sub-class to the super-class during construction you should pass it as a parameter. But this is a different use-case to what you are describing and the sub-class would probably not have your own field corresponding to the getter anyway.

If you have any "special" initialisation code, put that in a separate private method and call it from both the constructor and the setter separately.

Setter methods or constructors

You should use the constructor approach, when you want to create a new instance of the object, with the values already populated(a ready to use object with value populated). This way you need not explicitly call the setter methods for each field in the object to populate them.

You set the value using a setter approach, when you want to change the value of a field, after the object has been created.

For example:-

MyObject obj1 = new MyObject("setSomeStringInMyObject"); // Constructor approach
// Yippy, I can just use my obj1, as the values are already populated
// But even after this I can change the value
obj1.setSomeString("IWantANewValue"); // Value changed using setter, if required.
..
MyObject obj2 = new MyObject();
obj2.setSomeString("setSomeStringNow"); // Setter approach
// values weren't populated - I had to do that. Sad :(

And as Axel mentioned, if you want to create immutable objects, you cannot use setter-methods approach. I won't say everything has to be initialised in the constructor because different approaches exist, like lazy-evaluation which can be used even with immutable objects.

What exacly happens when a class constructor calls a setter

The new keyword creates an object with the prototype of Person, then calls the constructor. So by the time the constructor is called, it already has that object, and that object has a pair of setters and getters for this.fullname. If you attempt to assign to this.fullname, the standard behavior for setters and getters occurs, and the setter will be called. The behavior doesn't get modified due to being inside a constructor function.

May I use setters in constructors?

Regarding

“I know I shouldn't call non-private setters directly to avoid problems if the setter gets overwritten in a derived class.”

This is largely not a problem. Even with virtual setters, the definitions used when constructing a class A are the ones for dynamic type A. C++ is safe that way, as opposed to Java and C# (where you risk that a virtual call ends up in derived class code before the base class invariant has been established, and bang).

Regarding best practice, it is to be critical of setters and getters. They do have a purpose in a language with introspection, where e.g. "designer" tools can use them, but not so much in C++. So, best practice is to always ask, do I really need them, can I design some other way (e.g. move instead of setxy (which may not sound very different, but consider a call from a constructor – move doesn't make so much sense during construction)).

Using setter methods in constructor: bad practice?

It's probably not a good idea. If you don't make that class final and don't make the setName( ... ) method private or final someone else is able to extend your class and overrid the setName( ... ) method. Your constructor (in your base class) will call that method in the extending class instead of your implementation. Nobody knows what that method can do. As a rule of thumb: a constructor shouldn't call methods that can be overriden.

In Java, can you call a setter for one class inside a constructor for another class?

Yes, absolutely. Why would you not be able to?

class Boo {
private String name;

public void setName(String name) {
this.name = name;
}
}

class Foo {
private final Boo boo;

public Foo() {
boo = new Boo();
boo.setName("boo");
}
}

The fact that you ask the question suggests there's something you think might go wrong - what in particular did you have in mind?

Using setters in constructor

Yes, it is recommended to do this, basically for the reason you already mentioned.

On the other hand you should ask yourself if you need the setter at all and not directly implement the checks inside the constructor. The reason I am writing this is that setters in general result in mutable state which has many disadvantages as opposed to immutable classes. However sometimes they are required.

Another recommendation: If your class variable is an object and you can modify the constructor of this object, you could put the check into the constructor of this object:

class MyFoo {
public:
MyFoo(int value) {
if (value < 42) {
throw invalid_argument{"Foo < 42."};
}
v = value;
}
private:
int v;
}

This will enable you to use an initialization list in the constructor of your Test class:

Test(int foo) : foo(foo) {}

However, now the check is a property of the class of the variable and no longer one of the owning class.



Related Topics



Leave a reply



Submit