Classes & OOP: Constructors

Roger PoonBy Roger Poon

JS++ Designer and Project Lead

In our cat example, we've been able to instantiate our cat and provide a name separately. However, it may be desirable to require the cat to be named at instantiation so that we don't accidentally forget to name a cat. Constructors allow us to control instantiation.

By default, JS++ provides a constructor for you. This is known as the "default constructor." It is implicitly defined by JS++ if you do not have any constructors that you've explicitly defined. The default constructor takes no arguments and only returns a new instance of the class. To understand the default constructor, we can explicitly define it:

    external $;

    module Animals
    {
        class Cat
        {
            string _name;

            var $element = $(
                """
                <div class="animal">
                    <i class="icofont icofont-animal-cat"></i>
                </div>
                """
            );

            Cat() {
            }

            property string name() {
                return _name;
            }
            property void name(string name) {
                _name = name;
            }

            void render() {
                $element.attr("title", _name);
                $("#content").append($element);
            }
        }
    }
    

If you try to compile the project, there should be no problems. The reason is because we are instantiating the 'Cat' class without arguments in our main.jspp file. If you try to provide a few arguments, you will get a compile error for incorrect code.

As you can see from our explicitly-defined default constructor, the constructor has no parameters. Additionally, it doesn't do anything. (Constructors with no actions will still return a new instance of the class. Explicit 'return' statements inside constructors are unnecessary and not allowed because constructors always return a new instance of the class.)

One particular use for constructors is to initialize fields to custom values. Right now, if you instantiate the 'Cat' class, you will get the '_name' field as an empty string. If we want instances of 'Cat' to always have a name, we must require it during instantiation by specifying a constructor.

First, remove the getter and setter methods. Second, change the explicit constructor we defined to take one parameter: a 'string' for the cat's name. Finally, initialize the field to the argument provided to the constructor. (You should know how to do this by now.)

Your code in Cat.jspp should now look like this:

    external $;

    module Animals
    {
        class Cat
        {
            string _name;

            var $element = $(
                """
                <div class="animal">
                    <i class="icofont icofont-animal-cat"></i>
                </div>
                """
            );

            Cat(string name) {
                _name = name;
            }

            void render() {
                $element.attr("title", _name);
                $("#content").append($element);
            }
        }
    }
    

Next, we have to change main.jspp:

    import Animals;

    Cat cat1 = new Cat("Kitty");
    cat1.render();
    Cat cat2 = new Cat("Kat");
    cat2.render();
    

Compile the project. Open index.html in your web browser. You should see the two cats again. Hover over their images. You should once again see their names.

It's important to note that the implicitly-defined default constructor (that takes zero arguments) is no longer defined. Once you explicitly define a constructor for a class, the default constructor will not be explicitly defined. Thus, the only way to instantiate our 'Cat' class now is to use the constructor that requires a name. If you try to change the code in main.jspp to instantiate a class with zero arguments, you will get a compile error.