Programing tip: Constructors
10 11 Mar 2016 20:28 by u/roznak
The point of a constructor is to allocate memory and initialize something.
The tip is make your constructor in such a way that it only contains the absolute necessary code that can't trigger an exception or slow down.
Move the code that does make the code slow or can have error in a separate method. This way it tells the user of that class that it is a method and can be slow or create errors.
9 comments
1 u/SwiftLion 11 Mar 2016 21:02
As a corrolary, you should always be aware of the life cycle of the framework you’re using. Using iOS as an example, a “view controller” has some methods that are called exactly once, at least once, or every time a certain event occurs. The subtleties of these timings can be easy to miss and cause strange behavior.
1 u/zquad 11 Mar 2016 22:29
Another tip is to call on setters to set class members instead of doing so in the constructor. Eg. Instead of
Don't
constructor(Member member) { this.member; } public setMember(Member member){ this.member = member }
Do
constructor(Member member) { this.setMember(member); } public setMember(Member member){ this.member = member }
Why? Do won't need to rewrite validation logic. And the latter is consistent with separation of responsibility.
1 u/roznak [OP] 11 Mar 2016 23:04
Reformatted for clarity. (check out the <> button) to write code.
Don't
Do
0 u/zquad 12 Mar 2016 00:07
Thanks
1 u/Tecktonik 11 Mar 2016 23:21
Now you have created a public setter method for a property that maybe shouldn't be publicly settable. For a private property, you certainly don't want a public setter, but creating a private setter seems excessive.
Many post-Java languages use implicit setter methods which avoid the clutter of such boilerplate methods.
0 u/Tecktonik 11 Mar 2016 23:35
You have to strike a balance with how much work is done in a constructor. If you move "unnecessary" code out of the constructor, but still require some kind of init() to be called, then you will end up building Factories, and you can never have just one Factory. But if the factory is calling the slow Init() code you moved out of the constructor, all you have done is added complexity for no actual benefit.
1 u/roznak [OP] 12 Mar 2016 00:21
But the Init() can also be reused to recycle an object that was already created. That class might be only used in your factory but that code could maybe also reused outside the factory in future projects.
Now comes the interesting part, when you go to multi threading usage of that class. You can create the classes fast in one thread and then let the slower Init() execute in parallel threads.It simplifies your code to track what objects initialized successfully and which ones failed.
In small scale projects, of course Init() might be overkill, but my experience is that code gets recycled and ends up in bigger projects. And the fact that you see Init() in a class is a warning that this class could have a speed penalty when you use it.
When you design the class with Init() up front first, then later you can always optimize your code by commenting it out and see where the compiler stops. It is harder to find in your code all locations where the classes gets created and add the init().
1 u/Tecktonik 12 Mar 2016 02:01
This seems kind of like an argument against "You aren't going to need it!" by saying "It will turn out useful later on." Of course that is how a lot of Factory classes get started in the first place. The underlying intention is to prevent technical debt: give an object a life cycle, first construct, then initialize, so you don't have to pay off the debt of adding the life cycle later on. The downside of this is that changes to init() might screw up the life cycle in an invisible way, so you still have to track down all the places where the class is instantiated to make sure they still work, because if you don't you must be willing to eat the technical debt you were only pretending to avoid in the first place. It is a risk either way.
If you are repurposing an init() method to recycle an object, you create a sizable risk of introducing inconsistent state, or possibly leaking data from the old state into the new state. You can't safely use init() to turn an old object into a just-like-new object unless your init() method also restores sensitive properties to their default values - something an init() method wouldn't normally be concerned with.
0 u/roznak [OP] 12 Mar 2016 02:32
The art of software :-) Many different solutions with many different outcomes.
But there is more in life than just factories ;-)
Also if the initial constructor takes 100ms to execute because it has some loading code and you move that 99.9 ms to the Init() then the execution penalty to call Init() is maybe a few microseconds.