www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Virtual templates members

reply "JS" <js.mdnq gmail.com> writes:
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
parent reply "Nicolas Sicard" <dransic gmail.com> writes:
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
next sibling parent reply "JS" <js.mdnq gmail.com> writes:
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:
 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(); } ---
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.
Aug 08 2013
parent reply "Nicolas Sicard" <dransic gmail.com> writes:
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:
 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(); } ---
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.
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.
Aug 08 2013
parent "JS" <js.mdnq gmail.com> writes:
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:
 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:
 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(); } ---
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.
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.
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).
Aug 08 2013
prev sibling parent "Dicebot" <public dicebot.lv> writes:
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