Unexpected constructor execution with subclasses - bug?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
1
down vote

favorite












I've distilled a real-world issue down to an example to show my question:



public class SubclassTrial 

virtual class BaseClass
public string label get; set;
public integer value get; set;

public BaseClass(string pLabel)
this.label = 'B1: ' + pLabel;
this.value = 0;


public BaseClass(string pLabel, integer pValue)
this('B2: ' + pLabel);
this.value = pValue;



class SubClass extends BaseClass
public SubClass(string pLabel)
super('S1: ' + pLabel);


public SubClass(string pLabel, integer pValue)
super('S2: ' + pLabel, pValue);



public static void testIt()
SubClass s = new Subclass('test', 2);
system.debug(s.label);
system.assertEquals('B1: S1: B2: S2: test', s.label);





When TestIt() runs, it creates a SubClass using the 2-argument constructor, which uses super to call BaseClass's 2-argument constructor. That in turn calls this(string) - a 1-argument constructor for the calling class. I would expect that to invoke SubClass(string) due to polymorphism, not BaseClass(string), since the actual class instance is a SubClass. But that isn't happening; my assertion fails:



System.AssertException: Assertion Failed: 
Expected: B1: S1: B2: S2: test,
Actual: B1: B2: S2: test


The Apex docs don't really cover the intricacies of overridden constructors too well, so I haven't been able to find any concrete explanation. Why is this(string) calling the BaseClass version instead of the Subclass version when the calling class is a SubClass?



EDIT to clarify: a couple of answers have suggested I'm wrong in my assumptions; and in particular @sfdcfox states, "There is no way, during construction, for the parent class to call any method of the child's class, including other child constructors, virtual, or abstract methods." This is not my experience, which is why I expected the other behavior. I've expanded my trial class to show this, by adding otherLabel, which is set by a virtual method. If you run this, you will see that the first assertion (of otherLabel) passes, and only the second assertion (label) fails. Specifically, the BaseClass constructor calls this.setOtherLabel(), which invokes SubClass.setOtherLabel(). I expected this() to follow the same pattern.



public class SubclassTrial2 

virtual class BaseClass
public string label get; set;
public string otherLabel get; set;
public integer value get; set;

public BaseClass(string pLabel)
this.label = 'B1: ' + pLabel;
this.setOtherLabel(pLabel);
this.value = 0;


public BaseClass(string pLabel, integer pValue)
this('B2: ' + pLabel);
this.value = pValue;


public virtual void setOtherLabel(string pOtherLabel)
this.otherLabel = 'B: ' + pOtherLabel;



class SubClass extends BaseClass
public SubClass(string pLabel)
super('S1: ' + pLabel);


public SubClass(string pLabel, integer pValue)
super('S2: ' + pLabel, pValue);


public override void setOtherLabel(string pOtherLabel)
this.otherLabel = 'S: ' + pOtherLabel;



public static void testIt()
SubClass s = new Subclass('test', 2);
system.debug(s.label);
system.debug(s.otherLabel);
system.assertEquals('S: B2: S2: test', s.otherLabel);
system.assertEquals('B1: S1: B2: S2: test', s.label);












share|improve this question





























    up vote
    1
    down vote

    favorite












    I've distilled a real-world issue down to an example to show my question:



    public class SubclassTrial 

    virtual class BaseClass
    public string label get; set;
    public integer value get; set;

    public BaseClass(string pLabel)
    this.label = 'B1: ' + pLabel;
    this.value = 0;


    public BaseClass(string pLabel, integer pValue)
    this('B2: ' + pLabel);
    this.value = pValue;



    class SubClass extends BaseClass
    public SubClass(string pLabel)
    super('S1: ' + pLabel);


    public SubClass(string pLabel, integer pValue)
    super('S2: ' + pLabel, pValue);



    public static void testIt()
    SubClass s = new Subclass('test', 2);
    system.debug(s.label);
    system.assertEquals('B1: S1: B2: S2: test', s.label);





    When TestIt() runs, it creates a SubClass using the 2-argument constructor, which uses super to call BaseClass's 2-argument constructor. That in turn calls this(string) - a 1-argument constructor for the calling class. I would expect that to invoke SubClass(string) due to polymorphism, not BaseClass(string), since the actual class instance is a SubClass. But that isn't happening; my assertion fails:



    System.AssertException: Assertion Failed: 
    Expected: B1: S1: B2: S2: test,
    Actual: B1: B2: S2: test


    The Apex docs don't really cover the intricacies of overridden constructors too well, so I haven't been able to find any concrete explanation. Why is this(string) calling the BaseClass version instead of the Subclass version when the calling class is a SubClass?



    EDIT to clarify: a couple of answers have suggested I'm wrong in my assumptions; and in particular @sfdcfox states, "There is no way, during construction, for the parent class to call any method of the child's class, including other child constructors, virtual, or abstract methods." This is not my experience, which is why I expected the other behavior. I've expanded my trial class to show this, by adding otherLabel, which is set by a virtual method. If you run this, you will see that the first assertion (of otherLabel) passes, and only the second assertion (label) fails. Specifically, the BaseClass constructor calls this.setOtherLabel(), which invokes SubClass.setOtherLabel(). I expected this() to follow the same pattern.



    public class SubclassTrial2 

    virtual class BaseClass
    public string label get; set;
    public string otherLabel get; set;
    public integer value get; set;

    public BaseClass(string pLabel)
    this.label = 'B1: ' + pLabel;
    this.setOtherLabel(pLabel);
    this.value = 0;


    public BaseClass(string pLabel, integer pValue)
    this('B2: ' + pLabel);
    this.value = pValue;


    public virtual void setOtherLabel(string pOtherLabel)
    this.otherLabel = 'B: ' + pOtherLabel;



    class SubClass extends BaseClass
    public SubClass(string pLabel)
    super('S1: ' + pLabel);


    public SubClass(string pLabel, integer pValue)
    super('S2: ' + pLabel, pValue);


    public override void setOtherLabel(string pOtherLabel)
    this.otherLabel = 'S: ' + pOtherLabel;



    public static void testIt()
    SubClass s = new Subclass('test', 2);
    system.debug(s.label);
    system.debug(s.otherLabel);
    system.assertEquals('S: B2: S2: test', s.otherLabel);
    system.assertEquals('B1: S1: B2: S2: test', s.label);












    share|improve this question

























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      I've distilled a real-world issue down to an example to show my question:



      public class SubclassTrial 

      virtual class BaseClass
      public string label get; set;
      public integer value get; set;

      public BaseClass(string pLabel)
      this.label = 'B1: ' + pLabel;
      this.value = 0;


      public BaseClass(string pLabel, integer pValue)
      this('B2: ' + pLabel);
      this.value = pValue;



      class SubClass extends BaseClass
      public SubClass(string pLabel)
      super('S1: ' + pLabel);


      public SubClass(string pLabel, integer pValue)
      super('S2: ' + pLabel, pValue);



      public static void testIt()
      SubClass s = new Subclass('test', 2);
      system.debug(s.label);
      system.assertEquals('B1: S1: B2: S2: test', s.label);





      When TestIt() runs, it creates a SubClass using the 2-argument constructor, which uses super to call BaseClass's 2-argument constructor. That in turn calls this(string) - a 1-argument constructor for the calling class. I would expect that to invoke SubClass(string) due to polymorphism, not BaseClass(string), since the actual class instance is a SubClass. But that isn't happening; my assertion fails:



      System.AssertException: Assertion Failed: 
      Expected: B1: S1: B2: S2: test,
      Actual: B1: B2: S2: test


      The Apex docs don't really cover the intricacies of overridden constructors too well, so I haven't been able to find any concrete explanation. Why is this(string) calling the BaseClass version instead of the Subclass version when the calling class is a SubClass?



      EDIT to clarify: a couple of answers have suggested I'm wrong in my assumptions; and in particular @sfdcfox states, "There is no way, during construction, for the parent class to call any method of the child's class, including other child constructors, virtual, or abstract methods." This is not my experience, which is why I expected the other behavior. I've expanded my trial class to show this, by adding otherLabel, which is set by a virtual method. If you run this, you will see that the first assertion (of otherLabel) passes, and only the second assertion (label) fails. Specifically, the BaseClass constructor calls this.setOtherLabel(), which invokes SubClass.setOtherLabel(). I expected this() to follow the same pattern.



      public class SubclassTrial2 

      virtual class BaseClass
      public string label get; set;
      public string otherLabel get; set;
      public integer value get; set;

      public BaseClass(string pLabel)
      this.label = 'B1: ' + pLabel;
      this.setOtherLabel(pLabel);
      this.value = 0;


      public BaseClass(string pLabel, integer pValue)
      this('B2: ' + pLabel);
      this.value = pValue;


      public virtual void setOtherLabel(string pOtherLabel)
      this.otherLabel = 'B: ' + pOtherLabel;



      class SubClass extends BaseClass
      public SubClass(string pLabel)
      super('S1: ' + pLabel);


      public SubClass(string pLabel, integer pValue)
      super('S2: ' + pLabel, pValue);


      public override void setOtherLabel(string pOtherLabel)
      this.otherLabel = 'S: ' + pOtherLabel;



      public static void testIt()
      SubClass s = new Subclass('test', 2);
      system.debug(s.label);
      system.debug(s.otherLabel);
      system.assertEquals('S: B2: S2: test', s.otherLabel);
      system.assertEquals('B1: S1: B2: S2: test', s.label);












      share|improve this question















      I've distilled a real-world issue down to an example to show my question:



      public class SubclassTrial 

      virtual class BaseClass
      public string label get; set;
      public integer value get; set;

      public BaseClass(string pLabel)
      this.label = 'B1: ' + pLabel;
      this.value = 0;


      public BaseClass(string pLabel, integer pValue)
      this('B2: ' + pLabel);
      this.value = pValue;



      class SubClass extends BaseClass
      public SubClass(string pLabel)
      super('S1: ' + pLabel);


      public SubClass(string pLabel, integer pValue)
      super('S2: ' + pLabel, pValue);



      public static void testIt()
      SubClass s = new Subclass('test', 2);
      system.debug(s.label);
      system.assertEquals('B1: S1: B2: S2: test', s.label);





      When TestIt() runs, it creates a SubClass using the 2-argument constructor, which uses super to call BaseClass's 2-argument constructor. That in turn calls this(string) - a 1-argument constructor for the calling class. I would expect that to invoke SubClass(string) due to polymorphism, not BaseClass(string), since the actual class instance is a SubClass. But that isn't happening; my assertion fails:



      System.AssertException: Assertion Failed: 
      Expected: B1: S1: B2: S2: test,
      Actual: B1: B2: S2: test


      The Apex docs don't really cover the intricacies of overridden constructors too well, so I haven't been able to find any concrete explanation. Why is this(string) calling the BaseClass version instead of the Subclass version when the calling class is a SubClass?



      EDIT to clarify: a couple of answers have suggested I'm wrong in my assumptions; and in particular @sfdcfox states, "There is no way, during construction, for the parent class to call any method of the child's class, including other child constructors, virtual, or abstract methods." This is not my experience, which is why I expected the other behavior. I've expanded my trial class to show this, by adding otherLabel, which is set by a virtual method. If you run this, you will see that the first assertion (of otherLabel) passes, and only the second assertion (label) fails. Specifically, the BaseClass constructor calls this.setOtherLabel(), which invokes SubClass.setOtherLabel(). I expected this() to follow the same pattern.



      public class SubclassTrial2 

      virtual class BaseClass
      public string label get; set;
      public string otherLabel get; set;
      public integer value get; set;

      public BaseClass(string pLabel)
      this.label = 'B1: ' + pLabel;
      this.setOtherLabel(pLabel);
      this.value = 0;


      public BaseClass(string pLabel, integer pValue)
      this('B2: ' + pLabel);
      this.value = pValue;


      public virtual void setOtherLabel(string pOtherLabel)
      this.otherLabel = 'B: ' + pOtherLabel;



      class SubClass extends BaseClass
      public SubClass(string pLabel)
      super('S1: ' + pLabel);


      public SubClass(string pLabel, integer pValue)
      super('S2: ' + pLabel, pValue);


      public override void setOtherLabel(string pOtherLabel)
      this.otherLabel = 'S: ' + pOtherLabel;



      public static void testIt()
      SubClass s = new Subclass('test', 2);
      system.debug(s.label);
      system.debug(s.otherLabel);
      system.assertEquals('S: B2: S2: test', s.otherLabel);
      system.assertEquals('B1: S1: B2: S2: test', s.label);









      apex polymorphism






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 12 mins ago

























      asked 1 hour ago









      Jason Clark

      5,98122967




      5,98122967




















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          2
          down vote













          Yes, this is working as designed. Inside a constructor, this(...) calls the matching constructor in the current class, and super calls the matching constructor in the parent class. There is no way, during construction, for the parent class to call any method of the child's class, including other child constructors, virtual, or abstract methods. You're most likely going to need to implement some sort of factory pattern so you can take advantage of virtual methods.






          share|improve this answer




















          • I've added a second example to show that a base class's constructor can call child class methods virtually. Not saying your are wrong about how this(...) is behaving, but want to show why I expect it to work the other way.
            – Jason Clark
            11 mins ago

















          up vote
          1
          down vote













          This is working exactly as I would expect it to but I suppose I'm not as Object Oriented as others.



          this is inside the constructor for BaseClass and as such this refers to BaseClass and not SubClass.



          I would think that if this was Javascript it might work the way you are expecting as this in js is very different from this in most c based languages. In Javascript this is much more contextual and is based more on the calling context than the defining context.






          share|improve this answer




















            Your Answer







            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "459"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsalesforce.stackexchange.com%2fquestions%2f233656%2funexpected-constructor-execution-with-subclasses-bug%23new-answer', 'question_page');

            );

            Post as a guest






























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            2
            down vote













            Yes, this is working as designed. Inside a constructor, this(...) calls the matching constructor in the current class, and super calls the matching constructor in the parent class. There is no way, during construction, for the parent class to call any method of the child's class, including other child constructors, virtual, or abstract methods. You're most likely going to need to implement some sort of factory pattern so you can take advantage of virtual methods.






            share|improve this answer




















            • I've added a second example to show that a base class's constructor can call child class methods virtually. Not saying your are wrong about how this(...) is behaving, but want to show why I expect it to work the other way.
              – Jason Clark
              11 mins ago














            up vote
            2
            down vote













            Yes, this is working as designed. Inside a constructor, this(...) calls the matching constructor in the current class, and super calls the matching constructor in the parent class. There is no way, during construction, for the parent class to call any method of the child's class, including other child constructors, virtual, or abstract methods. You're most likely going to need to implement some sort of factory pattern so you can take advantage of virtual methods.






            share|improve this answer




















            • I've added a second example to show that a base class's constructor can call child class methods virtually. Not saying your are wrong about how this(...) is behaving, but want to show why I expect it to work the other way.
              – Jason Clark
              11 mins ago












            up vote
            2
            down vote










            up vote
            2
            down vote









            Yes, this is working as designed. Inside a constructor, this(...) calls the matching constructor in the current class, and super calls the matching constructor in the parent class. There is no way, during construction, for the parent class to call any method of the child's class, including other child constructors, virtual, or abstract methods. You're most likely going to need to implement some sort of factory pattern so you can take advantage of virtual methods.






            share|improve this answer












            Yes, this is working as designed. Inside a constructor, this(...) calls the matching constructor in the current class, and super calls the matching constructor in the parent class. There is no way, during construction, for the parent class to call any method of the child's class, including other child constructors, virtual, or abstract methods. You're most likely going to need to implement some sort of factory pattern so you can take advantage of virtual methods.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 42 mins ago









            sfdcfox

            229k10176390




            229k10176390











            • I've added a second example to show that a base class's constructor can call child class methods virtually. Not saying your are wrong about how this(...) is behaving, but want to show why I expect it to work the other way.
              – Jason Clark
              11 mins ago
















            • I've added a second example to show that a base class's constructor can call child class methods virtually. Not saying your are wrong about how this(...) is behaving, but want to show why I expect it to work the other way.
              – Jason Clark
              11 mins ago















            I've added a second example to show that a base class's constructor can call child class methods virtually. Not saying your are wrong about how this(...) is behaving, but want to show why I expect it to work the other way.
            – Jason Clark
            11 mins ago




            I've added a second example to show that a base class's constructor can call child class methods virtually. Not saying your are wrong about how this(...) is behaving, but want to show why I expect it to work the other way.
            – Jason Clark
            11 mins ago












            up vote
            1
            down vote













            This is working exactly as I would expect it to but I suppose I'm not as Object Oriented as others.



            this is inside the constructor for BaseClass and as such this refers to BaseClass and not SubClass.



            I would think that if this was Javascript it might work the way you are expecting as this in js is very different from this in most c based languages. In Javascript this is much more contextual and is based more on the calling context than the defining context.






            share|improve this answer
























              up vote
              1
              down vote













              This is working exactly as I would expect it to but I suppose I'm not as Object Oriented as others.



              this is inside the constructor for BaseClass and as such this refers to BaseClass and not SubClass.



              I would think that if this was Javascript it might work the way you are expecting as this in js is very different from this in most c based languages. In Javascript this is much more contextual and is based more on the calling context than the defining context.






              share|improve this answer






















                up vote
                1
                down vote










                up vote
                1
                down vote









                This is working exactly as I would expect it to but I suppose I'm not as Object Oriented as others.



                this is inside the constructor for BaseClass and as such this refers to BaseClass and not SubClass.



                I would think that if this was Javascript it might work the way you are expecting as this in js is very different from this in most c based languages. In Javascript this is much more contextual and is based more on the calling context than the defining context.






                share|improve this answer












                This is working exactly as I would expect it to but I suppose I'm not as Object Oriented as others.



                this is inside the constructor for BaseClass and as such this refers to BaseClass and not SubClass.



                I would think that if this was Javascript it might work the way you are expecting as this in js is very different from this in most c based languages. In Javascript this is much more contextual and is based more on the calling context than the defining context.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 1 hour ago









                gNerb

                5,322634




                5,322634



























                     

                    draft saved


                    draft discarded















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsalesforce.stackexchange.com%2fquestions%2f233656%2funexpected-constructor-execution-with-subclasses-bug%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Comments

                    Popular posts from this blog

                    What does second last employer means? [closed]

                    Installing NextGIS Connect into QGIS 3?

                    One-line joke