Monday 20 January 2020

Constructors

I've been reviewing lately (with some help from: [1] and [2] how default constructors, calls from the derived constructor to the parent one and so on... in both JavaScript and C#, work, and it'll be good to serialize it here.

JavaScript

If we don't define a explicit constructor in our class the compiler will add a default one for us. In a base class it'll just add this:

constructor( ) { }

and in a child class this:

constructor(...args) {
    super(...args);
}

So the child default constructor will call the base constructor passing over all the parameters it has received. This is possible cause in our dynamic JavaScript regardless of the arity defined in a function signature we can call it passing as many parameters as we want, then the function will use them or not.

C#

If we don't define a constructor in a base class the compiler will add a default constructor (a parameterless one). In a derived class, if we don't define a constructor, the compiler will try to add a parameterless contructor that will call the parameterless constructor in the base class. If the base class lacks that parameterless constructor (for example it has one expecting a string) we'll get a compilation error:

There is no argument given that corresponds to the required formal parameter 'a' of 'Parent4.Parent4(string)'

There's an important difference between JavaScript and C#. In C#, if we don't write a explicit call from a explicit derived constructor to the parent constructor, and the parent constructor has a parameterless one (explicit or implicit) the C# compiler will add a call to this constructor (base()). This is different in JavaScript, the compiler won't add a super() call from a explicit constructor, we'll have to add it ourselves, otherwise we'll get an error like this:

ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor

If you want to see some code:

JavaScript

class Parent1{
 constructor(){
  console.log("Parent1: " + Array.from(arguments));
 }
}

class Child1 extends Parent1{
 //no need to declare a constructor, the implicit one added by the compiler will call the base one with all the parameters
}

//Parent constructor gets called from the default Child constructor with the parameters list
new Child1("Bonjour", "Bonsoir");
 
console.log("----------------------");
 
class Parent2{
 constructor(){
  console.log("Parent1: " + Array.from(arguments));
 }
}

//I need to explicitly call the Parent constructor (contrary to C# where if the Parent has a parameterless constructor the base() call is atomatically added), otherwise we get an error:
//ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
class Child2 extends Parent2{
 constructor(){
  super(...arguments);
  console.log("Child2: " + Array.from(arguments));

 }
}

C#

    class Parent1{
        public Parent1(){
            Console.WriteLine("Parent1");
        }
    }

    class Child1: Parent1
    {
        //the default parameterless constructor invokes the Parent parameterless constructor
    }

    //----------------------------------
        
    class Parent2
    {
    }

    class Child2: Parent2{
        //it invokes the Parent default, Parameterless constructor (base())
        public Child2(string a)
        {
            Console.WriteLine("Child2");
        }
    }

    //----------------------------------

    
    class Parent3
    {
        public Parent3()
        {
            Console.WriteLine("Parent3");
        }
    }

    
    class Child3: Parent3{
        //No need to explicitly call the Parent constructor, compiler already adds a base() call
        public Child3(string a)
        {
            Console.WriteLine("Child3");
        }
    }

    //----------------------------------


    class Parent4
    {
        public Parent4(string a)
        {
            Console.WriteLine("Parent4");
        }
    }

    //I need to explicitly call the Parent constructor 
    class Child4: Parent4{
    //public Child4(string a)
    //the above does not compile as there's not a parameterless constructor in the base class
    //"There is no argument given that corresponds to the required formal parameter 'a' of 'Parent4.Parent4(string)'"
 
    public Child4(string a): base(a)
    {
  Console.WriteLine("Child4");
 }
}

No comments:

Post a Comment