www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template this parameter in constructor

reply Vlad Leberstein <zeronineseven gmail.com> writes:
Hi! I'm struggling to use "Template This Parameters" feature(as 
described in 
https://dlang.org/spec/template.html#TemplateThisParameter) in 
class constructor. But it's usage isn't documented very clearly 
and I'm not even sure if it's supposed to work this way. Consider 
the following example:

class C1 {
	this(this This)() {
		pragma(msg, "C1 constructor: "~__traits(identifier, This));	
	}
}


class C2 : C1 {
	this(this This)() {
		pragma(msg, "C2 constructor: "~__traits(identifier, This));
		super();
	}
}


class C3 : C2 {
	this(this This)() {
		pragma(msg, "C3 constructor: "~__traits(identifier, This));
		super();
	}
	
}


int main(string[] args) {
	auto test = new C3();
	
	return 0;
}

The output is:
C3 constructor: C3
C2 constructor: C3
C1 constructor: C2

As you can see this works but doesn't produce the desired 
behavior - we can't get static type of the C3 class in C1 
constructor. I suspect that it's somehow related to the fact that 
templated functions can't be virtual.

And here comes the question: Is this a bug or the way things are 
supposed to work(and hence should be documented)?

It would be immensely helpful to have such kind of compile-time 
information(for usecases vastly similar to what's described in 
http://forum.dlang.org/thread/mailman.1403.1361371073.22503.digitalm
rs-d puremagic.com) cause currently I'm using some kind of CRTP pattern with
multilevel inheritance support instead and it feels very very very weird in D
world.

Thanks in advance!
Feb 21 2016
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/21/16 11:48 AM, Vlad Leberstein wrote:
 Hi! I'm struggling to use "Template This Parameters" feature(as
 described in https://dlang.org/spec/template.html#TemplateThisParameter)
 in class constructor. But it's usage isn't documented very clearly and
 I'm not even sure if it's supposed to work this way. Consider the
 following example:

 class C1 {
      this(this This)() {
          pragma(msg, "C1 constructor: "~__traits(identifier, This));
      }
 }


 class C2 : C1 {
      this(this This)() {
          pragma(msg, "C2 constructor: "~__traits(identifier, This));
          super();
      }
 }


 class C3 : C2 {
      this(this This)() {
          pragma(msg, "C3 constructor: "~__traits(identifier, This));
          super();
      }

 }


 int main(string[] args) {
      auto test = new C3();

      return 0;
 }

 The output is:
 C3 constructor: C3
 C2 constructor: C3
 C1 constructor: C2

 As you can see this works but doesn't produce the desired behavior - we
 can't get static type of the C3 class in C1 constructor. I suspect that
 it's somehow related to the fact that templated functions can't be virtual.

 And here comes the question: Is this a bug or the way things are
 supposed to work(and hence should be documented)?
This isn't a bug. Here is what happens. 1. template this is assigned the compile-time type of the object *when the function is called*. 2. A base class constructor is called from the next derived constructor. So C2's constructor is called from C3's, and C1's constructor is called from C2's. So it follows that the template this type will be the next derived constructor (or the type itself if that is the most derived type), because that's the compile-time type the object's ctor is called with.
 It would be immensely helpful to have such kind of compile-time
 information(for usecases vastly similar to what's described in
 http://forum.dlang.org/thread/mailman.1403.1361371073.22503.digitalmars-d puremagic.com)
 cause currently I'm using some kind of CRTP pattern with multilevel
 inheritance support instead and it feels very very very weird in D world.
I think you may be able to do something like this: this(T = typeof(this))() { super!T(); } But I'm not sure if it works. -Steve
Feb 21 2016
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 02/21/2016 01:48 PM, Steven Schveighoffer wrote:

 So it follows that the template this type will be the next derived
 constructor (or the type itself if that is the most derived type),
I've just checked: Adding a C4 to the interitance chain (and constructing a C4) confirms that to be the case: C4 constructor: C4 C3 constructor: C4 C2 constructor: C3 C1 constructor: C2 Ali
Feb 21 2016
prev sibling parent Vlad Leberstein <zeronineseven gmail.com> writes:
On Sunday, 21 February 2016 at 21:48:21 UTC, Steven Schveighoffer 
wrote:
 This isn't a bug. Here is what happens.

 1. template this is assigned the compile-time type of the 
 object *when the function is called*.

 2. A base class constructor is called from the next derived 
 constructor. So C2's constructor is called from C3's, and C1's 
 constructor is called from C2's.

 So it follows that the template this type will be the next 
 derived constructor (or the type itself if that is the most 
 derived type), because that's the compile-time type the 
 object's ctor is called with.
Many thanks to both of you, Steven and Ali! Now this makes much more sense!
 I think you may be able to do something like this:

 this(T = typeof(this))()
 {
    super!T();
 }

 But I'm not sure if it works.
class C1 { this(This = typeof(this))() { pragma(msg, "C1 constructor: "~__traits(identifier, This)); } } class C2 : C1 { this(This = typeof(this))() { pragma(msg, "C2 constructor: "~__traits(identifier, This)); super.__ctor!This(); } } class C3 : C2 { this(This = typeof(this))() { pragma(msg, "C3 constructor: "~__traits(identifier, This)); super.__ctor!This(); } } int main(string[] args) { auto test = new C3(); return 0; } Compilation output: C3 constructor: C3 C2 constructor: C3 C1 constructor: C3 C1 constructor: C1 C2 constructor: C2 C1 constructor: C2 A little bit modified solution compiles but doesn't work as expected(tested on dmd 2.070) and produces some quite strange results and I really don't get why. But now it's not critical for me cause I managed to solve my initial problem with major refactoring. Many thanks again!
Feb 26 2016