digitalmars.D.learn - Virtual templates members
- JS (52/52) Aug 07 2013 The following code is used to reduce dependence on new and the
- Nicolas Sicard (49/101) Aug 08 2013 Why not make it a mixin template?
- JS (6/123) Aug 08 2013 Because I don't want to have to specify this in each class. iNew
- Nicolas Sicard (5/135) Aug 08 2013 I understand the goal. But if someone forgets to add the mixin,
- JS (25/161) Aug 08 2013 But it is backwards. If you are designing a class and forget,
- Dicebot (5/5) Aug 08 2013 Actually "mixin New!()" should be enough, as typeof(this)
The following code is used to reduce dependence on new and the GC. iNew is used as the replacement. The problem is, where ever New is used, it requires typing the type twice. e.g., A.New!A(...) instead of A.New(...) Is there any way to solve this issue? (iNew is suppose to provide the contract to implement a "new" like method that will allocate the class. Note there is no virtual function so no overhead) import std.stdio, std.conv; enum eNew { Default = 0, } interface iNew { final static T New(T, A...)(A args) { eNew type = eNew.Default; static if (A.length == 0 || !is(typeof(args[0]) == eNew)) alias nargs = args; else { type = cast(eNew)args[0]; alias nargs = args[1..$]; } writeln(">> ", __traits(classInstanceSize, T)); switch (type) { default: return new T(nargs); } return new T(nargs); } } class A : iNew { int t; } class B : A { int q; double d; } void main() { A a = A.New!A(); B b = B.New!B(); readln(); }
Aug 07 2013
On Thursday, 8 August 2013 at 01:48:49 UTC, JS wrote:The following code is used to reduce dependence on new and the GC. iNew is used as the replacement. The problem is, where ever New is used, it requires typing the type twice. e.g., A.New!A(...) instead of A.New(...) Is there any way to solve this issue? (iNew is suppose to provide the contract to implement a "new" like method that will allocate the class. Note there is no virtual function so no overhead) import std.stdio, std.conv; enum eNew { Default = 0, } interface iNew { final static T New(T, A...)(A args) { eNew type = eNew.Default; static if (A.length == 0 || !is(typeof(args[0]) == eNew)) alias nargs = args; else { type = cast(eNew)args[0]; alias nargs = args[1..$]; } writeln(">> ", __traits(classInstanceSize, T)); switch (type) { default: return new T(nargs); } return new T(nargs); } } class A : iNew { int t; } class B : A { int q; double d; } void main() { A a = A.New!A(); B b = B.New!B(); readln(); }Why not make it a mixin template? --- import std.stdio, std.conv; enum eNew { Default = 0, } mixin template iNew(T) { final static T New(A...)(A args) { eNew type = eNew.Default; static if (A.length == 0 || !is(typeof(args[0]) == eNew)) alias nargs = args; else { type = cast(eNew)args[0]; alias nargs = args[1..$]; } writeln(">> ", __traits(classInstanceSize, T)); switch (type) { default: return new T(nargs); } //return new T(nargs); } } class A { mixin iNew!A; int t; } class B : A { mixin iNew!B; int q; double d; } void main() { A a = A.New(); B b = B.New(); readln(); } ---
Aug 08 2013
On Thursday, 8 August 2013 at 07:21:19 UTC, Nicolas Sicard wrote:On Thursday, 8 August 2013 at 01:48:49 UTC, JS wrote:Because I don't want to have to specify this in each class. iNew is suppose to be a contract. What happens if someone writes a class and forgets to add the mixin then distributes the class in a library? There's no issue with that using an interface because it results in an error.The following code is used to reduce dependence on new and the GC. iNew is used as the replacement. The problem is, where ever New is used, it requires typing the type twice. e.g., A.New!A(...) instead of A.New(...) Is there any way to solve this issue? (iNew is suppose to provide the contract to implement a "new" like method that will allocate the class. Note there is no virtual function so no overhead) import std.stdio, std.conv; enum eNew { Default = 0, } interface iNew { final static T New(T, A...)(A args) { eNew type = eNew.Default; static if (A.length == 0 || !is(typeof(args[0]) == eNew)) alias nargs = args; else { type = cast(eNew)args[0]; alias nargs = args[1..$]; } writeln(">> ", __traits(classInstanceSize, T)); switch (type) { default: return new T(nargs); } return new T(nargs); } } class A : iNew { int t; } class B : A { int q; double d; } void main() { A a = A.New!A(); B b = B.New!B(); readln(); }Why not make it a mixin template? --- import std.stdio, std.conv; enum eNew { Default = 0, } mixin template iNew(T) { final static T New(A...)(A args) { eNew type = eNew.Default; static if (A.length == 0 || !is(typeof(args[0]) == eNew)) alias nargs = args; else { type = cast(eNew)args[0]; alias nargs = args[1..$]; } writeln(">> ", __traits(classInstanceSize, T)); switch (type) { default: return new T(nargs); } //return new T(nargs); } } class A { mixin iNew!A; int t; } class B : A { mixin iNew!B; int q; double d; } void main() { A a = A.New(); B b = B.New(); readln(); } ---
Aug 08 2013
On Thursday, 8 August 2013 at 16:58:37 UTC, JS wrote:On Thursday, 8 August 2013 at 07:21:19 UTC, Nicolas Sicard wrote:I understand the goal. But if someone forgets to add the mixin, A.New() would not compile. And the probability of mistakenly calling 'new A' might even be as high as the probability of forgetting the mixin.On Thursday, 8 August 2013 at 01:48:49 UTC, JS wrote:Because I don't want to have to specify this in each class. iNew is suppose to be a contract. What happens if someone writes a class and forgets to add the mixin then distributes the class in a library? There's no issue with that using an interface because it results in an error.The following code is used to reduce dependence on new and the GC. iNew is used as the replacement. The problem is, where ever New is used, it requires typing the type twice. e.g., A.New!A(...) instead of A.New(...) Is there any way to solve this issue? (iNew is suppose to provide the contract to implement a "new" like method that will allocate the class. Note there is no virtual function so no overhead) import std.stdio, std.conv; enum eNew { Default = 0, } interface iNew { final static T New(T, A...)(A args) { eNew type = eNew.Default; static if (A.length == 0 || !is(typeof(args[0]) == eNew)) alias nargs = args; else { type = cast(eNew)args[0]; alias nargs = args[1..$]; } writeln(">> ", __traits(classInstanceSize, T)); switch (type) { default: return new T(nargs); } return new T(nargs); } } class A : iNew { int t; } class B : A { int q; double d; } void main() { A a = A.New!A(); B b = B.New!B(); readln(); }Why not make it a mixin template? --- import std.stdio, std.conv; enum eNew { Default = 0, } mixin template iNew(T) { final static T New(A...)(A args) { eNew type = eNew.Default; static if (A.length == 0 || !is(typeof(args[0]) == eNew)) alias nargs = args; else { type = cast(eNew)args[0]; alias nargs = args[1..$]; } writeln(">> ", __traits(classInstanceSize, T)); switch (type) { default: return new T(nargs); } //return new T(nargs); } } class A { mixin iNew!A; int t; } class B : A { mixin iNew!B; int q; double d; } void main() { A a = A.New(); B b = B.New(); readln(); } ---
Aug 08 2013
On Thursday, 8 August 2013 at 17:32:56 UTC, Nicolas Sicard wrote:On Thursday, 8 August 2013 at 16:58:37 UTC, JS wrote:But it is backwards. If you are designing a class and forget, then distribute a library of that class, everyone is screwed if you forget to include the appropriate member. Not only will they not be able to call it, as you said, they won't easily be able to fix it. With interfaces, it provides the contract. With the static final, it provides a single instance(doesn't have to mixin at each class). I realize it probably doesn't matter too much in the long run but I'm asking how to make what I want work and not a workaround. It would be nice to have a This which returns the type of the interface, analogous to this, which returns the instance. After all, I could just write a standard template and use that regardless and call it directly. Then there is no need to use mixins which waste space. e.g., T New(T, A...)(A args) { } Then just New!A(...) but then I loose my interface contract, which, in this scenario isn't a huge deal but I'd like to be able to distinguish objects that have this allocation strategy pattern vs those that don't. In the future, I may want to allow the class to provide it's own allocation scheme overriding iNew.New(indirectly).On Thursday, 8 August 2013 at 07:21:19 UTC, Nicolas Sicard wrote:I understand the goal. But if someone forgets to add the mixin, A.New() would not compile. And the probability of mistakenly calling 'new A' might even be as high as the probability of forgetting the mixin.On Thursday, 8 August 2013 at 01:48:49 UTC, JS wrote:Because I don't want to have to specify this in each class. iNew is suppose to be a contract. What happens if someone writes a class and forgets to add the mixin then distributes the class in a library? There's no issue with that using an interface because it results in an error.The following code is used to reduce dependence on new and the GC. iNew is used as the replacement. The problem is, where ever New is used, it requires typing the type twice. e.g., A.New!A(...) instead of A.New(...) Is there any way to solve this issue? (iNew is suppose to provide the contract to implement a "new" like method that will allocate the class. Note there is no virtual function so no overhead) import std.stdio, std.conv; enum eNew { Default = 0, } interface iNew { final static T New(T, A...)(A args) { eNew type = eNew.Default; static if (A.length == 0 || !is(typeof(args[0]) == eNew)) alias nargs = args; else { type = cast(eNew)args[0]; alias nargs = args[1..$]; } writeln(">> ", __traits(classInstanceSize, T)); switch (type) { default: return new T(nargs); } return new T(nargs); } } class A : iNew { int t; } class B : A { int q; double d; } void main() { A a = A.New!A(); B b = B.New!B(); readln(); }Why not make it a mixin template? --- import std.stdio, std.conv; enum eNew { Default = 0, } mixin template iNew(T) { final static T New(A...)(A args) { eNew type = eNew.Default; static if (A.length == 0 || !is(typeof(args[0]) == eNew)) alias nargs = args; else { type = cast(eNew)args[0]; alias nargs = args[1..$]; } writeln(">> ", __traits(classInstanceSize, T)); switch (type) { default: return new T(nargs); } //return new T(nargs); } } class A { mixin iNew!A; int t; } class B : A { mixin iNew!B; int q; double d; } void main() { A a = A.New(); B b = B.New(); readln(); } ---
Aug 08 2013
Actually "mixin New!()" should be enough, as typeof(this) resolves to enclosing type in template mixins. And inheritance brings nothing over mixins in terms of guarantees - forgetting to use proper Base or use proper method is almost the same level of accident.
Aug 08 2013