www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template mixins and struct constructors

reply Adrian Matoga <dlang.spam matoga.info> writes:
I can do this:

struct Foo {
	int a;
	string b;
	this(int a) { this.a = a; }
	this(Args...)(string b, auto ref Args args) { this.b = b; 
this(args); }
}

unittest {
	auto foo1 = Foo(5);
	auto foo2 = Foo("foo", 15);
}

However, the following code is invalid:

mixin template AddField(T) {
	T b;
	this(Args...)(T b, auto ref Args args)
	{
		this.b = b;
		this(args);
	}
}

struct Bar {
	mixin AddField!string;
	int a;
	this(int a) { this.a = a; }
}

unittest {
	auto bar1 = Bar(5);
	auto bar2 = Bar("bar", 15);  // line 31
}

sctor.d(31): Error: constructor sctor.Bar.this (int a) is not 
callable using argument types (string, int)

Is it by design or is it a bug?
And, if it is by design, what is the reason for that?
Mar 02 2016
next sibling parent reply Daniel Kozak <kozzi11 gmail.com> writes:
On Wednesday, 2 March 2016 at 12:27:04 UTC, Adrian Matoga wrote:
 I can do this:

 struct Foo {
 	int a;
 	string b;
 	this(int a) { this.a = a; }
 	this(Args...)(string b, auto ref Args args) { this.b = b; 
 this(args); }
 }

 unittest {
 	auto foo1 = Foo(5);
 	auto foo2 = Foo("foo", 15);
 }

 However, the following code is invalid:

 mixin template AddField(T) {
 	T b;
 	this(Args...)(T b, auto ref Args args)
 	{
 		this.b = b;
 		this(args);
 	}
 }

 struct Bar {
 	mixin AddField!string;
 	int a;
 	this(int a) { this.a = a; }
 }

 unittest {
 	auto bar1 = Bar(5);
 	auto bar2 = Bar("bar", 15);  // line 31
 }

 sctor.d(31): Error: constructor sctor.Bar.this (int a) is not 
 callable using argument types (string, int)

 Is it by design or is it a bug?
 And, if it is by design, what is the reason for that?
You can use string mixins: template AddField(T) { enum AddField = T.stringof ~ ` b; this(Args...)(` ~ T.stringof ~ ` b, auto ref Args args) { this.b = b; this(args); }`; } struct Bar { mixin(AddField!string); int a; this(int a) { this.a = a; } } unittest { auto bar1 = Bar(5); auto bar2 = Bar("bar", 15); // line 31 }
Mar 02 2016
parent reply Adrian Matoga <dlang.spam matoga.info> writes:
On Wednesday, 2 March 2016 at 12:48:47 UTC, Daniel Kozak wrote:
 On Wednesday, 2 March 2016 at 12:27:04 UTC, Adrian Matoga wrote:
 (...)
You can use string mixins: template AddField(T) { enum AddField = T.stringof ~ ` b; this(Args...)(` ~ T.stringof ~ ` b, auto ref Args args) { this.b = b; this(args); }`; } struct Bar { mixin(AddField!string); int a; this(int a) { this.a = a; } } unittest { auto bar1 = Bar(5); auto bar2 = Bar("bar", 15); // line 31 }
What if T is private type in some other module or, even worse, a Voldemort type?
Mar 02 2016
parent reply Daniel Kozak <kozzi11 gmail.com> writes:
On Wednesday, 2 March 2016 at 13:18:23 UTC, Adrian Matoga wrote:
 On Wednesday, 2 March 2016 at 12:48:47 UTC, Daniel Kozak wrote:
 On Wednesday, 2 March 2016 at 12:27:04 UTC, Adrian Matoga 
 wrote:
 (...)
You can use string mixins: template AddField(T) { enum AddField = T.stringof ~ ` b; this(Args...)(` ~ T.stringof ~ ` b, auto ref Args args) { this.b = b; this(args); }`; } struct Bar { mixin(AddField!string); int a; this(int a) { this.a = a; } } unittest { auto bar1 = Bar(5); auto bar2 = Bar("bar", 15); // line 31 }
What if T is private type in some other module or, even worse, a Voldemort type?
OK maybe this one: template AddField(T) { T b; this(Args...)(T b, auto ref Args args) { this.b = b; this(args); } this(int a) { this.a = a; } } struct Bar { int a; mixin AddField!(string); } unittest { auto bar1 = Bar(5); auto bar2 = Bar("bar", 15); }
Mar 02 2016
parent reply Adrian Matoga <dlang.spam matoga.info> writes:
On Wednesday, 2 March 2016 at 14:36:59 UTC, Daniel Kozak wrote:
 OK maybe this one:

 template AddField(T) {
     T b;
     this(Args...)(T b, auto ref Args args)
     {
            this.b = b;
        this(args);
     }
     this(int a) {
         this.a = a;
     }
 }

 struct Bar {
     int a;
     mixin AddField!(string);
 }

 unittest {
     auto bar1 = Bar(5);
     auto bar2 = Bar("bar", 15);
 }
Then it's limited to structs in which only "int a" is to be initialized. Not very useful and the templated ctor is not needed now. struct Baz { mixin AddField!string; // fail, no "int a" in Baz. ulong d; double x; string foo; }
Mar 02 2016
parent Daniel Kozak <kozzi11 gmail.com> writes:
On Wednesday, 2 March 2016 at 14:50:15 UTC, Adrian Matoga wrote:
 On Wednesday, 2 March 2016 at 14:36:59 UTC, Daniel Kozak wrote:
 OK maybe this one:

 template AddField(T) {
     T b;
     this(Args...)(T b, auto ref Args args)
     {
            this.b = b;
        this(args);
     }
     this(int a) {
         this.a = a;
     }
 }

 struct Bar {
     int a;
     mixin AddField!(string);
 }

 unittest {
     auto bar1 = Bar(5);
     auto bar2 = Bar("bar", 15);
 }
Then it's limited to structs in which only "int a" is to be initialized. Not very useful and the templated ctor is not needed now. struct Baz { mixin AddField!string; // fail, no "int a" in Baz. ulong d; double x; string foo; }
OK then: mixin template AddField(T) { T b; auto ref constructor(Args...)(T b, auto ref Args args) { typeof(this) r; r.b = b; r.__ctor(args); return r; } } struct Bar { mixin AddField!string; int a; this(int a) { this.a = a; } alias __ctor = constructor; } unittest { import std.stdio; auto bar1 = Bar(5); auto bar2 = Bar("bar", 15); writeln(bar1); writeln(bar2); }
Mar 02 2016
prev sibling next sibling parent Daniel Kozak <kozzi11 gmail.com> writes:
On Wednesday, 2 March 2016 at 12:27:04 UTC, Adrian Matoga wrote:
 I can do this:

 struct Foo {
 	int a;
 	string b;
 	this(int a) { this.a = a; }
 	this(Args...)(string b, auto ref Args args) { this.b = b; 
 this(args); }
 }

 unittest {
 	auto foo1 = Foo(5);
 	auto foo2 = Foo("foo", 15);
 }

 However, the following code is invalid:

 mixin template AddField(T) {
 	T b;
 	this(Args...)(T b, auto ref Args args)
 	{
 		this.b = b;
 		this(args);
 	}
 }

 struct Bar {
 	mixin AddField!string;
 	int a;
 	this(int a) { this.a = a; }
 }

 unittest {
 	auto bar1 = Bar(5);
 	auto bar2 = Bar("bar", 15);  // line 31
 }

 sctor.d(31): Error: constructor sctor.Bar.this (int a) is not 
 callable using argument types (string, int)

 Is it by design or is it a bug?
 And, if it is by design, what is the reason for that?
I would say it is by design. What this will generate is something like: struct Bar { static struct _scope { string b; this(Args...)(string b, auto ref Args args) { this.b = b; this(args); } } int a; this(int a) { this.a = a; } }
Mar 02 2016
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 2 March 2016 at 12:27:04 UTC, Adrian Matoga wrote:
 Is it by design or is it a bug?
 And, if it is by design, what is the reason for that?
That's by design. It allows you to override names from a template mixin like inheritance but no runtime cost. Read my tip of the week here to see how it works and how you can combine ctors from a mixin: http://arsdnet.net/this-week-in-d/2016-feb-07.html
Mar 02 2016
next sibling parent Daniel Kozak via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
Dne 2.3.2016 v 21:39 Adam D. Ruppe via Digitalmars-d-learn napsal(a):
 On Wednesday, 2 March 2016 at 12:27:04 UTC, Adrian Matoga wrote:
 Is it by design or is it a bug?
 And, if it is by design, what is the reason for that?
That's by design. It allows you to override names from a template mixin like inheritance but no runtime cost. Read my tip of the week here to see how it works and how you can combine ctors from a mixin: http://arsdnet.net/this-week-in-d/2016-feb-07.html
I know it :). I need to upgrade my memory. I spent all day looking for it in D cookbook, because I was sure it was you who make this tip somewhere.
Mar 02 2016
prev sibling parent Adrian Matoga <dlang.spam matoga.info> writes:
On Wednesday, 2 March 2016 at 20:39:57 UTC, Adam D. Ruppe wrote:
 On Wednesday, 2 March 2016 at 12:27:04 UTC, Adrian Matoga wrote:
 Is it by design or is it a bug?
 And, if it is by design, what is the reason for that?
That's by design. It allows you to override names from a template mixin like inheritance but no runtime cost. Read my tip of the week here to see how it works and how you can combine ctors from a mixin: http://arsdnet.net/this-week-in-d/2016-feb-07.html
Ah, I was on vacation at that time so that's why I don't remember reading it. :) Thanks! It's a nice workaround but it's, well, a workaround. It leaks the internals of the template mixin and a potential API user would have to remember two additional quirks when using it. I guess I'll try a different approach, initializing the mixed in members later with a function.
Mar 03 2016