Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I throw an exception in constructors

Tags:

oop

typescript

If I have a triangle class, like so:

export default class Triangle {

    sides: number[]

    constructor(...sides: number[]) {
        this.sides = sides
    }

    kind() {
        // returns type of triangle
    {
}

and if the sides passed into the constructor do not create a real triangle, is it better to throw the error when the class is created (e.g. in the constructor), or when the function(s) are called?

There is this answer, that says it's okay in Java, and I'm sure it works in TypeScript. I'm just wanting to know if there are "best practices" in regards to OOP in general and TypeScript specifically.

like image 780
Logan Waite Avatar asked Jun 15 '19 22:06

Logan Waite


2 Answers

It is entirely acceptable to throw within the constructor. And usually the best practice is to fail fast and fail early. In your case for example, it is best to throw in the constructor, so that the error can be exposed early to the code responsible for sending the bad data. If you instead throw later when you actually use the triangle methods, the code that will be disrupted by that exception is not at fault (there's nothing they can do differently to prevent the exception). This usually means you will have to hunt down where the object was created, in order to resolve the error.

One of the main responsibilities of constructors in the first place is to ensure objects can only be created in a valid state. So not only is it acceptable to throw if the parameters would result in the object being in an invalid state, but this is right in line for why constructors exist in the first place.

like image 102
Daniel Tabuenca Avatar answered Sep 29 '22 19:09

Daniel Tabuenca


There is no correct answer, however you should always make "impossible" states "impossible" to represent, IE in this case a triangle will always have 3 sides so therefore just make any number of sides outside of this impossible to pass.

export default class Triangle {
    sides: number[]
    constructor(...sides: [number, number, number]) { // tuple now.
        this.sides = sides
    }
}


const test = new Triangle(2,2,2); // no error
const test1 = new Triangle(2,2,2,2) // Error can't have 4 sides.

The advantage of this is that whenever an invalid number of arugments is passes the program will fail at compile-time (safe) rather than runtime (unsafe)

like image 39
Shanon Jackson Avatar answered Sep 29 '22 18:09

Shanon Jackson