September 27, 2005
How about rather than delete the object add a Die method that marks it as dead. Then each time you need to check if an object is still alive, call a corresponding Alive method and if it isn’t, set the pointer you used to null. Just a thought.



In article <dhbveo$l6j$1@digitaldaemon.com>, Jarrett Billingsley says...
>
>"Triften Chmil" <Triften_member@pathlink.com> wrote in message news:dhaf74$2jkn$1@digitaldaemon.com...
>> So now I've basically got:
>>
>> MyObject mo = new MyObject();
>> MyObject mo2 = mo;
>> //mo2 is a reference to mo, right?
>>
>> delete(mo);
>> //this seems to cause no trouble
>> int x = mo2.myvar;
>> mo2.myFunc();
>>
>> I'd like to be able to check for deletion of the object referenced by mo
>> using
>> mo2. Is this possible?
>
>Nope.  Unless the GC were to keep a list of pointers to .. uhh, pointers that pointed to the objects, the GC has no way of setting mo2 to any value that says "this is an invalid object" (i.e. null).  mo gets set to null as the parameter to delete is actually an inout parameter (hence why you can't use an expression as the parameter to delete).
>
>This situation wouldn't really come up that often though.  Usually if you're deleting an object, you will get rid of all references to it, as all references to it will then be invalid.
>
>


September 28, 2005
Yeah, that was going to be my alternative.

So, eventually, all references to the object would be removed and the GC would come along is scrap it, right?

And if I could clarify something from the message from Jarrett: Is this:

delete(myOb);

equivalent to this:

myOb = null;

?

In article <dhccqs$1cgf$1@digitaldaemon.com>, BCS says...
>
>How about rather than delete the object add a Die method that marks it as dead. Then each time you need to check if an object is still alive, call a corresponding Alive method and if it isn’t, set the pointer you used to null. Just a thought.
>
>
>
>In article <dhbveo$l6j$1@digitaldaemon.com>, Jarrett Billingsley says...
>>
>>"Triften Chmil" <Triften_member@pathlink.com> wrote in message news:dhaf74$2jkn$1@digitaldaemon.com...
>>> So now I've basically got:
>>>
>>> MyObject mo = new MyObject();
>>> MyObject mo2 = mo;
>>> //mo2 is a reference to mo, right?
>>>
>>> delete(mo);
>>> //this seems to cause no trouble
>>> int x = mo2.myvar;
>>> mo2.myFunc();
>>>
>>> I'd like to be able to check for deletion of the object referenced by mo
>>> using
>>> mo2. Is this possible?
>>
>>Nope.  Unless the GC were to keep a list of pointers to .. uhh, pointers that pointed to the objects, the GC has no way of setting mo2 to any value that says "this is an invalid object" (i.e. null).  mo gets set to null as the parameter to delete is actually an inout parameter (hence why you can't use an expression as the parameter to delete).
>>
>>This situation wouldn't really come up that often though.  Usually if you're deleting an object, you will get rid of all references to it, as all references to it will then be invalid.
>>
>>
>
>




September 28, 2005
Triften Chmil wrote:
> Yeah, that was going to be my alternative.
> 
> So, eventually, all references to the object would be removed and the GC would
> come along is scrap it, right?
> 
> And if I could clarify something from the message from Jarrett:
> Is this:
> 
> delete(myOb);
> 
> equivalent to this:
> 
> myOb = null;
> 
> ?

Not strictly.  The expression:
# myOb = null;

just clears this particular Object-ref variable.  While the expression:
# delete myOb;

notifies the Garbage Collector that the Object ref'd by this variable is ripe for plucking.  (Normally it decides this for itself during periodic sweeps for references.  An object with no more valid ref's is ripe.)  There's no "guarantee" that the GC will deconstruct and delete the object immediately, but its been marked.

And in fact, you don't neccessarily need any Die method.  Just a basic "if (myOb !is null)" should suffice.  If you want to guarantee that the object you wanted deleted is bye-bye then use std.gc.fullCollect() to force the GC's hand:
# private import std.gc;
#
# // ...
# delete myOb;
# std.gc.fullCollect();

Unless I'm missing something, this should work just fine.

-- Chris Sauls
September 28, 2005
Actually the issue is that doing this:

MyObject mo = new MyObject();
MyObject mo2 = mo;

delete(mo);

means that mo2 still references the other object and has no idea that the object has been "deleted". So doing a '!is null' on mo2 is not helpful.

In article <dhdcrg$25gs$1@digitaldaemon.com>, Chris Sauls says...
>
>Triften Chmil wrote:
>> Yeah, that was going to be my alternative.
>> 
>> So, eventually, all references to the object would be removed and the GC would come along is scrap it, right?
>> 
>> And if I could clarify something from the message from Jarrett: Is this:
>> 
>> delete(myOb);
>> 
>> equivalent to this:
>> 
>> myOb = null;
>> 
>> ?
>
>Not strictly.  The expression:
># myOb = null;
>
>just clears this particular Object-ref variable.  While the expression: # delete myOb;
>
>notifies the Garbage Collector that the Object ref'd by this variable is ripe for plucking.  (Normally it decides this for itself during periodic sweeps for references.  An object with no more valid ref's is ripe.)  There's no "guarantee" that the GC will deconstruct and delete the object immediately, but its been marked.
>
>And in fact, you don't neccessarily need any Die method.  Just a basic "if (myOb !is
>null)" should suffice.  If you want to guarantee that the object you wanted deleted is
>bye-bye then use std.gc.fullCollect() to force the GC's hand:
># private import std.gc;
>#
># // ...
># delete myOb;
># std.gc.fullCollect();
>
>Unless I'm missing something, this should work just fine.
>
>-- Chris Sauls


September 28, 2005
just FYI heres what Ive done on a commercial game engine for this kind of problem. I use a "reference target" and "reference origin" base classes. the reference targets simply contain a list of all origins that point to them (and the origin class is derived from the target but this is an implementation detail thats beside the point) this way your objects will  contain a list of referencing objects and it opens your framework up to do some pretty fancy yet simple stuff - like sending events from a target to all its reference origins when targets die or changes state. as for implementation i generally use a small "hook" class to manage connections between objects - essentially smart pointers that help synchronize these connections. for example i can have in my renderer a "multiple hook" of actors and inside my actor i would have a "single hook" to a renderer - attach a renderer to an actor and the actor is automatically connected to the renderer, etc. anyway Im rambling but my point is - Ive found a system like this to be magnitudes more flexible than the method you are wishing to employ. fyi

but this is one of the reasons I love D, implementing this kind of functionality in D is like a daydream compared to C++, and eek, dare I say almost "fun" :D  although I am missing some more complex functionality since i dont have a preprocessor but im still working around this. (but im hoping to eventually have a metaprogramming system to do some of this stuff out of the box)

anyway please let me know how your project goes, and good luck. I really like to see people using D for 3d engines because i think it can be used to build some amazing technology much easier compared to what we have been doing...


Triften Chmil wrote:

>
> I'm programming a shoot-em-up video game and a weapon that locks-on to an enemy
> keeps a pointer to that enemy and so can reference the enemy's location to track
> it. I want to make sure the enemy hasn't been destroyed before I try to lookup
> its locations.
>
> Unless my understanding of programming terms and methods is horribly off,
> passing a copy of the enemy object wouldn't do, because the location values
> would change, so you keep a pointer to the enemy object. I suppose you might use
> someother locating technique (an index in an array) which would basically still
> be a pointer.
>
> If I'm missing some particular aspect of the nature of D, please let me know.
> (I.E. pointers are evil, or some such.)
>
> Thanks again,
> Triften Chmil
September 28, 2005
"JT" <jtd514@ameritech.net> wrote in message news:dhedg5$3pj$1@digitaldaemon.com...

Hey, it's the (JT)Game .X export plugin guy :)

> just FYI heres what Ive done on a commercial game engine for this kind of problem. I use a "reference target" and "reference origin" base classes. the reference targets simply contain a list of all origins that point to them (and the origin class is derived from the target but this is an implementation detail thats beside the point) this way your objects will contain a list of referencing objects and it opens your framework up to do some pretty fancy yet simple stuff - like sending events from a target to all its reference origins when targets die or changes state. as for implementation i generally use a small "hook" class to manage connections between objects - essentially smart pointers that help synchronize these connections. for example i can have in my renderer a "multiple hook" of actors and inside my actor i would have a "single hook" to a renderer - attach a renderer to an actor and the actor is automatically connected to the renderer, etc. anyway Im rambling but my point is - Ive found a system like this to be magnitudes more flexible than the method you are wishing to employ. fyi
>
> but this is one of the reasons I love D, implementing this kind of functionality in D is like a daydream compared to C++, and eek, dare I say almost "fun" :D  although I am missing some more complex functionality since i dont have a preprocessor but im still working around this. (but im hoping to eventually have a metaprogramming system to do some of this stuff out of the box)

Just out of curiosity, what about the preprocessor do you miss?  Personally, I've not missed the preprocessor one bit.  You mention metaprogramming; I'm not sure how a preprocessor would help with that.  Then again, I never did much fancy stuff with the preprocessor in C++; it always seemed kind of hackish to me.

> anyway please let me know how your project goes, and good luck. I really like to see people using D for 3d engines because i think it can be used to build some amazing technology much easier compared to what we have been doing...

I hope you've seen nonagon, then!  The one thing that irks me about developing with DX9, though, is that I still feel like I'm using C++ when I use it, as there is no way for D to interface with the MDX runtimes. Managed DX in D would be a dream come true.  But oh well, checking for error codes isn't _that_ hard.


September 28, 2005
no thats not me. as for the preprocessor - what i miss is being able to construct classes and identifier names programatically. using my previous example - the macro: SINGLE_HOOK( cRenderer, Renderer );  could construct automatically an actual hook class and access methods called "Renderer" (like setRenderer() getRenderer() etc) i dont believe there is any way in D to construct identifier names. but again, D is so nice you generally never need this.

this is where metaobjects come in. please keep in mind, when I say metaprogramming i am not refering to C++ template metaprogramming. the template mp was nice but what im refering to is a metaobject protocol where the 'compiler metaobjects' are basically exposed to the language itself. quite simply, imagine during compile time being handed the compiler representation of your program and being given the ability to MODIFY anything before being sent to the back-end? this is called compile-time metaprogramming. given my previous example I could have the compiler itself generate my identifier names, whatever data structures and behaviors I need.

my previous example MACRO:

	SINGLE_HOOK( cRenderer, renderer );

could be changed to:

	singlehook cRenderer renderer;

and the 'singlehook' metahandler (most likely written in D) would be passed the tree for my program and it would build the code required for the feature add it to the tree and pass it back to the compiler for completion

of course this is just an example from C++, some of these techniques are not necessary in D but you get the idea...

btw if anyone knows how to generate identifier names in D please let me know.

I havent looked at nonagen very much but I plan on checking it out. i have never used managed direct x so im kind of unfamilar with that. i havent gotten into very much graphics programming in D as im still focused on building tools and procedures for solid D development in the future. but i will definately check out nonagen again...


Jarrett Billingsley wrote:
> "JT" <jtd514@ameritech.net> wrote in message news:dhedg5$3pj$1@digitaldaemon.com...
> 
> Hey, it's the (JT)Game .X export plugin guy :)
> 
> 
>>just FYI heres what Ive done on a commercial game engine for this kind of problem. I use a "reference target" and "reference origin" base classes. the reference targets simply contain a list of all origins that point to them (and the origin class is derived from the target but this is an implementation detail thats beside the point) this way your objects will contain a list of referencing objects and it opens your framework up to do some pretty fancy yet simple stuff - like sending events from a target to all its reference origins when targets die or changes state. as for implementation i generally use a small "hook" class to manage connections between objects - essentially smart pointers that help synchronize these connections. for example i can have in my renderer a "multiple hook" of actors and inside my actor i would have a "single hook" to a renderer - attach a renderer to an actor and the actor is automatically connected to the renderer, etc. anyway Im rambling but my point is - Ive found a system like this to be magnitudes more flexible than the method you are wishing to employ. fyi
>>
>>but this is one of the reasons I love D, implementing this kind of functionality in D is like a daydream compared to C++, and eek, dare I say almost "fun" :D  although I am missing some more complex functionality since i dont have a preprocessor but im still working around this. (but im hoping to eventually have a metaprogramming system to do some of this stuff out of the box)
> 
> 
> Just out of curiosity, what about the preprocessor do you miss?  Personally, I've not missed the preprocessor one bit.  You mention metaprogramming; I'm not sure how a preprocessor would help with that.  Then again, I never did much fancy stuff with the preprocessor in C++; it always seemed kind of hackish to me.
> 
> 
>>anyway please let me know how your project goes, and good luck. I really like to see people using D for 3d engines because i think it can be used to build some amazing technology much easier compared to what we have been doing...
> 
> 
> I hope you've seen nonagon, then!  The one thing that irks me about developing with DX9, though, is that I still feel like I'm using C++ when I use it, as there is no way for D to interface with the MDX runtimes. Managed DX in D would be a dream come true.  But oh well, checking for error codes isn't _that_ hard. 
> 
> 
September 28, 2005
Triften Chmil wrote:
> Actually the issue is that doing this:
> 
> MyObject mo = new MyObject();
> MyObject mo2 = mo;
> 
> delete(mo);
> 
> means that mo2 still references the other object and has no idea that the object
> has been "deleted". So doing a '!is null' on mo2 is not helpful.
> 

I just tested this, and sadly you're right.  I say sadly primarily because it isn't proper according to the D specs (if I'm reading them right).  The 'delete' expression should be immediately marking that object, and all that should be needed for it to be collected is a standard GC sweep, caused either by an allocation request or invoked directly with std.gc.fullCollect().  I'm curious as to why 'delete' is, apparently, not working.

-- Chris Sauls
September 28, 2005
Chris Sauls wrote:
> Triften Chmil wrote:
> 
>> Actually the issue is that doing this:
>>
>> MyObject mo = new MyObject();
>> MyObject mo2 = mo;
>>
>> delete(mo);
>>
>> means that mo2 still references the other object and has no idea that the object
>> has been "deleted". So doing a '!is null' on mo2 is not helpful.
>>
> 
> I just tested this, and sadly you're right.  I say sadly primarily because it isn't proper according to the D specs (if I'm reading them right).  The 'delete' expression should be immediately marking that object, and all that should be needed for it to be collected is a standard GC sweep, caused either by an allocation request or invoked directly with std.gc.fullCollect().  I'm curious as to why 'delete' is, apparently, not working.
> 
> -- Chris Sauls

That is not delete's job.  Delete's job is to inform the GC that the object is ready for deletion.  Such maintenance with making sure that dangling references to that object are cleaned up is solely up to the programmer.  Effectively, you've told the garbage collector to collect something which is not 'garbage'. =P
September 28, 2005
On Wed, 28 Sep 2005 14:39:22 -0500, James Dunne <james.jdunne@gmail.com> wrote:
> Chris Sauls wrote:
>> Triften Chmil wrote:
>>
>>> Actually the issue is that doing this:
>>>
>>> MyObject mo = new MyObject();
>>> MyObject mo2 = mo;
>>>
>>> delete(mo);
>>>
>>> means that mo2 still references the other object and has no idea that the object
>>> has been "deleted". So doing a '!is null' on mo2 is not helpful.
>>>
>>  I just tested this, and sadly you're right.  I say sadly primarily because it isn't proper according to the D specs (if I'm reading them right).  The 'delete' expression should be immediately marking that object, and all that should be needed for it to be collected is a standard GC sweep, caused either by an allocation request or invoked directly with std.gc.fullCollect().  I'm curious as to why 'delete' is, apparently, not working.
>>  -- Chris Sauls
>
> That is not delete's job.  Delete's job is to inform the GC that the object is ready for deletion.  Such maintenance with making sure that dangling references to that object are cleaned up is solely up to the programmer.  Effectively, you've told the garbage collector to collect something which is not 'garbage'. =P

The solution is a reference counted pointer of some sort. However, it cannot work exactly like a C++ one might due to the inability to overload the assignment operator. Instead we can use the constructor, so, where you would say:

RefPtr s = new RefPtr(o);
RefPtr p;
p = s;

Instead you have to say:

RefPtr s = new RefPtr(o);
RefPtr p;
p = new RefPtr(s);

Essentially replace any/all assignments of RefPtr's with a 'new' statement.

Below is an implementation and test program for it. Note I use 'auto' to ensure the reference is deleted at the end of scope. If you cannot do that you _must_ instead call delete manually.

Forgetting to do either will introduce the possibility that the destructor for RefPtr is never called, the reference count will be wrong, and the resource will not be free'd. In fact, failing to auto/delete RefPtr will likely mean the destructor for the resource is _never_ called.

The garbage collector will still collect the memory at some stage, i.e. when there are no live references to it.

My opinion remains that the inability to create a solid reference counting implementation is a weakness in D. I agree that it's 'seldom' required (due to D being garbage collected) but when you need one, you need something solid, reliable and flexible enough to handle the different use cases. The current situation is too easy to break. Destruction is non-deterministic and therefore unreliable.

import std.c.windows.windows;
import std.random;
import std.thread;
import std.stdio;

class RefPtr
{
	RefPtr parent;
	Object resource = null;
	int refs = 0;

	this(Object res)
	{
		resource = res;
		writefln("ThreadID=(",Thread.getThis().id,") Initial RefPtr for resource=(",resource,")");
		increment();		
	}

	this(RefPtr rhs)
	{
		parent = rhs;
		parent.increment();
		writefln("ThreadID=(",Thread.getThis().id,") Ref=(",parent.refs,") for resource=(",parent.resource,")");
	}
	
	~this()
	{
		int r;
		
		if ((r = decrement()) == 0)
		{
			writefln("ThreadID=(",Thread.getThis().id,") release last ref Ref=(",r,")");
			if (parent) parent = null;
			else if (resource)
			{
				writefln("ThreadID=(",Thread.getThis().id,") delete resource=(",resource,")");
				delete resource;
				resource = null;
			}
		}
		writefln("ThreadID=(",Thread.getThis().id,") release Ref=(",r,")");
	}
protected:
	int increment()
	{
		int ret;
		
		if (parent) ret = parent.increment();
		else {
			synchronized(this)
			{
				ret = ++refs;
				writefln("ThreadID=(",Thread.getThis().id,") increment to Ref=(",refs,")");
			}
		}
		
		return ret;
	}
	int decrement()
	{
		int ret;
		
		if (parent) ret = parent.decrement();
		else {
			synchronized(this)
			{
				ret = --refs;
				writefln("ThreadID=(",Thread.getThis().id,") decrement to Ref=(",refs,")");
			}
		}
		
		return ret;
	}
}

class Resource
{
	char[] name = "11 was a racehorse";
	char[] toString() { return name; }
}

RefPtr pbob;

static this()
{
	pbob = new RefPtr(new Resource());
}

static ~this()
{
	delete pbob;
}

void main()
{
	Thread[] threads;
	int i;
	
	writefln("ThreadID=(",Thread.getThis().id,") is the main thread");
	
	for(i = 0; i < 10; i++)
	{
		threads ~= new Thread(&thread_function,null);
		threads[$-1].start();
	}
	
	while(true)
	{
		i = 0;
		foreach(Thread t; threads)
		{
			if (t.getState() == Thread.TS.TERMINATED) i++;
		}
		if (i == 10) break;
		Sleep(100);
	}
	
	writefln("Main exiting");
}

int thread_function(void* isnull)
{
	auto RefPtr p = new RefPtr(pbob);
	Sleep(1000+rand()%1000);	
	return 0;
}

Regan