www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - What is the best way to deal with this?

reply "Martin" <martinbbjerregaard gmail.com> writes:
	import std.stdio;

	class TestClass(T)
	{
	private:
		__gshared TestClass[] globalInstances;
	public:
		this()
		{
			globalInstances ~= this;
		}
		
		void test()
		{
			writeln("Address of variable globalInstances is: 0x", 
globalInstances.ptr);
		}
		
	}

	void main(string[] args)
	{
	
		TestClass!(int) t1 = new TestClass!(int);
		TestClass!(string) t2 = new TestClass!(string);
		
		t1.test;
		t2.test;
		
		readln;

	}

Outputs:
Address of variable globalInstances is: 0x4F3F80
Address of variable globalInstances is: 0x4F3F60

Which I guess makes sense since there's seperate globalInstances 
variables generated per template instance of the class. I want to 
store ALL instances, no matter if it's a TestClass!(int) or 
TestClass!(string) though.

Should I just use a __gshared void*[] globalInstances outside of 
the template and cast when necessary or is there an easier way 
that I'm too stupid to see? It's really late here...
Feb 23 2013
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, February 24, 2013 04:33:29 Martin wrote:
 	import std.stdio;
 
 	class TestClass(T)
 	{
 	private:
 		__gshared TestClass[] globalInstances;
 	public:
 		this()
 		{
 			globalInstances ~= this;
 		}
 
 		void test()
 		{
 			writeln("Address of variable globalInstances is: 0x",
 globalInstances.ptr);
 		}
 
 	}
 
 	void main(string[] args)
 	{
 
 		TestClass!(int) t1 = new TestClass!(int);
 		TestClass!(string) t2 = new TestClass!(string);
 
 		t1.test;
 		t2.test;
 
 		readln;
 
 	}
 
 Outputs:
 Address of variable globalInstances is: 0x4F3F80
 Address of variable globalInstances is: 0x4F3F60
 
 Which I guess makes sense since there's seperate globalInstances
 variables generated per template instance of the class. I want to
 store ALL instances, no matter if it's a TestClass!(int) or
 TestClass!(string) though.
 
 Should I just use a __gshared void*[] globalInstances outside of
 the template and cast when necessary or is there an easier way
 that I'm too stupid to see? It's really late here...

Every instance of a template is a completely different type than every other instance. They have no more relation to each other than class Foo {} and class Bar {} do. Remember that when you're instantiating a template, your literally generating code. It's basically a lot of copying and pasting by the compiler. If you want to store something for all instantiaties of a template, then it's going to need to be done outside of the template. However, I'd point out that in general, keeping track of every instance of a class isn't a good idea, and treating each instantiation of a template as if it had a relation to other instantiations of a template is also generally a bad idea. You may indeed have a use case where it makes sense, but my first inclination would be to suggest that you rethink whatever you're doing. - Jonathan M Davis
Feb 23 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/24/2013 04:59 AM, Steven Schveighoffer wrote:
 ...

 D is much different (and better IMO)
 ...

IMO The best way to think about it is that the two approaches are not comparable. D templates are a kind of hygienic macro system for declarations. Java does not have this. Java generics make the type system more expressive. D lacks this kind of expressiveness.
Feb 24 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/24/13 1:50 PM, Timon Gehr wrote:
 On 02/24/2013 04:59 AM, Steven Schveighoffer wrote:
 ...

 D is much different (and better IMO)
 ...

IMO The best way to think about it is that the two approaches are not comparable. D templates are a kind of hygienic macro system for declarations. Java does not have this. Java generics make the type system more expressive. D lacks this kind of expressiveness.

I'd think type erasure techniques make it possible to emulate Java's generics in D, whereas D's templates can't be emulated in Java. Andrei
Feb 24 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/24/2013 05:20 PM, Andrei Alexandrescu wrote:
 On 2/24/13 1:50 PM, Timon Gehr wrote:
 On 02/24/2013 04:59 AM, Steven Schveighoffer wrote:
 ...

 D is much different (and better IMO)
 ...

IMO The best way to think about it is that the two approaches are not comparable. D templates are a kind of hygienic macro system for declarations. Java does not have this. Java generics make the type system more expressive. D lacks this kind of expressiveness.

I'd think type erasure techniques make it possible to emulate Java's generics in D,

The compile-time type checking and avoidance of type erasure in user code aspects are the only important features of Java generics. This is most obvious noting that pre-generic Java also supports the techniques you mention.
  whereas D's templates can't be emulated in Java.

If type erasure is considered a means to emulate generics in D, then IMHO copy pasta should also be considered a means to emulate templates in Java. Otherwise the viewpoint could be considered biased. But I think usually they just use external code generation frameworks.
Feb 24 2013
prev sibling next sibling parent "Martin" <martinbbjerregaard gmail.com> writes:
On Sunday, 24 February 2013 at 03:45:41 UTC, Jonathan M Davis 
wrote:
 On Sunday, February 24, 2013 04:33:29 Martin wrote:
 	import std.stdio;
 
 	class TestClass(T)
 	{
 	private:
 		__gshared TestClass[] globalInstances;
 	public:
 		this()
 		{
 			globalInstances ~= this;
 		}
 
 		void test()
 		{
 			writeln("Address of variable globalInstances is: 0x",
 globalInstances.ptr);
 		}
 
 	}
 
 	void main(string[] args)
 	{
 
 		TestClass!(int) t1 = new TestClass!(int);
 		TestClass!(string) t2 = new TestClass!(string);
 
 		t1.test;
 		t2.test;
 
 		readln;
 
 	}
 
 Outputs:
 Address of variable globalInstances is: 0x4F3F80
 Address of variable globalInstances is: 0x4F3F60
 
 Which I guess makes sense since there's seperate 
 globalInstances
 variables generated per template instance of the class. I want 
 to
 store ALL instances, no matter if it's a TestClass!(int) or
 TestClass!(string) though.
 
 Should I just use a __gshared void*[] globalInstances outside 
 of
 the template and cast when necessary or is there an easier way
 that I'm too stupid to see? It's really late here...

Every instance of a template is a completely different type than every other instance. They have no more relation to each other than class Foo {} and class Bar {} do. Remember that when you're instantiating a template, your literally generating code. It's basically a lot of copying and pasting by the compiler. If you want to store something for all instantiaties of a template, then it's going to need to be done outside of the template. However, I'd point out that in general, keeping track of every instance of a class isn't a good idea, and treating each instantiation of a template as if it had a relation to other instantiations of a template is also generally a bad idea. You may indeed have a use case where it makes sense, but my first inclination would be to suggest that you rethink whatever you're doing. - Jonathan M Davis

Okay maybe that wasn't the best example - but what I'm wondering is: Is there a way to do like a TestClass<?> globalInstances like in Java?
Feb 23 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/24/13, Martin <martinbbjerregaard gmail.com> wrote:
 Should I just use a __gshared void*[] globalInstances outside of
 the template and cast when necessary..?

Technically they all inherit Object so you can use: __gshared Object[] globalInstances; As for where to put them: template TestClassWrap() { __gshared Object[] globalInstances; class TestClassWrap(T) { public: this() { globalInstances ~= this; } void test() { writeln("Address of variable globalInstances is: 0x", globalInstances.ptr); } } } alias TestClassWrap!() TestClass; void main(string[] args) { TestClass!(int) t1 = new TestClass!(int); TestClass!(string) t2 = new TestClass!(string); t1.test; t2.test; }
Feb 23 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/24/13, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 As for where to put them:

Just in case that didn't paste properly: http://codepad.org/SRWmIEcy
Feb 23 2013
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 23 Feb 2013 22:33:29 -0500, Martin <martinbbjerregaard gmail.com>  
wrote:

 	import std.stdio;

 	class TestClass(T)
 	{
 	private:
 		__gshared TestClass[] globalInstances;
 	public:
 		this()
 		{
 			globalInstances ~= this;
 		}
 		
 		void test()
 		{
 			writeln("Address of variable globalInstances is: 0x",  
 globalInstances.ptr);
 		}
 		
 	}

 	void main(string[] args)
 	{
 	
 		TestClass!(int) t1 = new TestClass!(int);
 		TestClass!(string) t2 = new TestClass!(string);
 		
 		t1.test;
 		t2.test;
 		
 		readln;

 	}

 Outputs:
 Address of variable globalInstances is: 0x4F3F80
 Address of variable globalInstances is: 0x4F3F60

 Which I guess makes sense since there's seperate globalInstances  
 variables generated per template instance of the class. I want to store  
 ALL instances, no matter if it's a TestClass!(int) or TestClass!(string)  
 though.

 Should I just use a __gshared void*[] globalInstances outside of the  
 template and cast when necessary or is there an easier way that I'm too  
 stupid to see? It's really late here...

You could create a base class for all: class TestBase { private: // or protected? __gshared TestBase[] globalInstances; ... // same as what you have } class TestClass(T) : TestBase { ... } Now, I have 2 points to make besides this. 1. The runtime is not especially equipped to deal with __gshared appending from multiple threads. Remember that __gshared is not a type constructor, so the runtime thinks this is a THREAD LOCAL array. Tread very cautiously with this kind of code. 2. Note that globalInstances is going to keep all your instances in memory, even if nothing else is referencing it. It's surprisingly difficult to avoid this problem. As I'm sure this is demonstration code and not your real code, I don't know your application enough to know if this is a problem. -Steve
Feb 23 2013
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 23 Feb 2013 22:53:20 -0500, Martin <martinbbjerregaard gmail.com>  
wrote:


 Okay maybe that wasn't the best example - but what I'm wondering is: Is  
 there a way to do like a TestClass<?> globalInstances like in Java?

Aha! This is java code :) Note that Java generics are NOT templates. Java uses one instantiation of code for all generic code. D is much different (and better IMO) -Steve
Feb 23 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/24/13, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 You could create a base class for all:

 class TestBase
 {
 private: // or protected?
     __gshared TestBase[] globalInstances;
 ... // same as what you have
 }

 class TestClass(T) : TestBase
 {
     ...
 }

Ah that's much better than my solution, cool. Mine was extracted from this enhancement request: http://d.puremagic.com/issues/show_bug.cgi?id=9088
Feb 23 2013
prev sibling parent "Martin" <martinbbjerregaard gmail.com> writes:
Thanks everyone, appreciate the help. Got all the answers I needed
Feb 23 2013