Jump to page: 1 2
Thread overview
What is the best way to deal with this?
Feb 24, 2013
Martin
Feb 24, 2013
Jonathan M Davis
Feb 24, 2013
Martin
Feb 24, 2013
Martin
Feb 24, 2013
Timon Gehr
Feb 24, 2013
Timon Gehr
Feb 24, 2013
Andrej Mitrovic
Feb 24, 2013
Andrej Mitrovic
Feb 24, 2013
Andrej Mitrovic
February 24, 2013
	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...
February 24, 2013
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
February 24, 2013
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?
February 24, 2013
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;
}
February 24, 2013
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
February 24, 2013
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
February 24, 2013
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
February 24, 2013
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
February 24, 2013
Thanks everyone, appreciate the help. Got all the answers I needed
February 24, 2013
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.
« First   ‹ Prev
1 2