Unexpected constructor execution with subclasses - bug?
Clash 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);
apex polymorphism
add a comment |Â
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);
apex polymorphism
add a comment |Â
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);
apex polymorphism
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
apex polymorphism
edited 12 mins ago
asked 1 hour ago
Jason Clark
5,98122967
5,98122967
add a comment |Â
add a comment |Â
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.
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 howthis(...)
is behaving, but want to show why I expect it to work the other way.
â Jason Clark
11 mins ago
add a comment |Â
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.
add a comment |Â
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.
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 howthis(...)
is behaving, but want to show why I expect it to work the other way.
â Jason Clark
11 mins ago
add a comment |Â
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.
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 howthis(...)
is behaving, but want to show why I expect it to work the other way.
â Jason Clark
11 mins ago
add a comment |Â
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.
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.
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 howthis(...)
is behaving, but want to show why I expect it to work the other way.
â Jason Clark
11 mins ago
add a comment |Â
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 howthis(...)
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
add a comment |Â
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.
add a comment |Â
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.
add a comment |Â
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.
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.
answered 1 hour ago
gNerb
5,322634
5,322634
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password