www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - delegating constructors and "this = ..."

reply jpf <spam example.com> writes:
Hi,
I've come across some strange behavior using delegating constructors and
assignment to this. Please have a look a this testcase:
--------------------------------------
class Test
{
	static Test[void*] lookupTable;
	public int i = 0;
	
	public this (void* ptr)
	{
		//Check if there already is a D object for this ptr
		if(ptr in lookupTable)
		{
			this = lookupTable[ptr];
			assert(this.i == 15);	/* ok */
			return;
		}
		
		i = 15;
		lookupTable[ptr] = this;
	}
	
	public this (void* ptr, bool fake)
	{
		this(ptr);
		assert(this.i == 15);	/* fails */
	}
}

void main()
{
	int a,b; /*for different pointers*/
	
	Test test1 = new Test(&a);
	Test test2 = new Test(&a);
	
	Test test3 = new Test(&b, false);
	Test test4 = new Test(&b, false);
	
	assert(test1 is test2); /* ok */
	assert(test2.i == 15);	/* ok */
	assert(test3 is test4); /* fails */
	assert(test4.i == 15);	/* fails */
}
--------------------------------------
Tested with dmd 1.055. As soon as the constructors are delegated the
code doesn't work anymore. The assignment "this = lookupTable[ptr];"
still succeeds but in the "this(void* ptr, bool fake)" constructor the
this reference seems wrong. The returned object also isn't the one
assigned to "this".

I'm not sure if this is a bug, but it's at least unexpected behavior.
Should I file a bug for this issue? Would the correct bug-tracker for
this be http://d.puremagic.com/issues ?
Feb 08 2010
parent reply BCS <none anon.com> writes:
Hello JPF,

 Hi,
 I've come across some strange behavior using delegating constructors
 and
 assignment to this. Please have a look a this testcase:
 --------------------------------------
 class Test
 {
 static Test[void*] lookupTable;
 public int i = 0;
 public this (void* ptr)
 {
 //Check if there already is a D object for this ptr
 if(ptr in lookupTable)
 {
 this = lookupTable[ptr];
 assert(this.i == 15);	/* ok */
 return;
 }

'this' is a mutable *local* reference (IIRC it is in fact a hidden 1st argument to the function). All the 'this =' lines does is assign to a local value that is discarded immediately. If asserts are turned off, the optimizer would even be free to just dump the then clause from that code as a dead assignment. ('this' being mutable might be considered a bug in the spec)
 

<IXOYE><
Feb 08 2010
next sibling parent jpf <spam example.com> writes:
On 08.02.2010 18:26, BCS wrote:
 
 'this' is a mutable *local* reference (IIRC it is in fact a hidden 1st
 argument to the function). All the 'this =' lines does is assign to a
 local value that is discarded immediately. If asserts are turned off,
 the optimizer would even be free to just dump the then clause from that
 code as a dead assignment.
 
 ('this' being mutable might be considered a bug in the spec)
 

<IXOYE><

this mentioned in the docs. I got the assigning idea from gtkd, they use this as well. One thing is strange though: If you look at the test case, in the end: ------------------------------------- Test test1 = new Test(&a); Test test2 = new Test(&a); assert(test1 is test2); /* ok */ ------------------------------------- This works, test1 and test2 reference the same object, which means "this = lookupTable[ptr];" does not only change the local reference when "this (void* ptr)" is invoked directly. If this is a local reference only, that shouldn't work at all, correct?
Feb 08 2010
prev sibling parent reply jpf <spam example.com> writes:
On 08.02.2010 18:26, BCS wrote:
 Hello JPF,
 
 Hi,
 I've come across some strange behavior using delegating constructors
 and
 assignment to this. Please have a look a this testcase:
 --------------------------------------
 class Test
 {
 static Test[void*] lookupTable;
 public int i = 0;
 public this (void* ptr)
 {
 //Check if there already is a D object for this ptr
 if(ptr in lookupTable)
 {
 this = lookupTable[ptr];
 assert(this.i == 15);    /* ok */
 return;
 }

'this' is a mutable *local* reference (IIRC it is in fact a hidden 1st argument to the function). All the 'this =' lines does is assign to a local value that is discarded immediately. If asserts are turned off, the optimizer would even be free to just dump the then clause from that code as a dead assignment. ('this' being mutable might be considered a bug in the spec)

<IXOYE><

'this' is a mutable local reference in the constructor but the constructor automatically returns the local 'this'. This explains why the first case works while the second doesn't. This would also mean I could do "this = this(ptr);" in the second constructor and it indeed does work; With the above change the whole testcase works as expected. I now just have to decide whether I'll use the "implementation specific but nice syntax" way or a static function instead of public constructors.
Feb 08 2010
parent reply BCS <none anon.com> writes:
Hello JPF,

 Thanks for your help, I think I now understand what's going on.
 'this' is a mutable local reference in the constructor but the
 constructor automatically returns the local 'this'. This explains why
 the first case works while the second doesn't. This would also mean I
 could do "this = this(ptr);" in the second constructor and it indeed
 does work; With the above change the whole testcase works as expected.

Odd....
 I now just have to decide whether I'll use the "implementation specific
 but nice syntax" way or a static function instead of public
 constructors.

don't use implementation specific code. I suggest you file a bug/clarification request. If that is the way things are supposed to work, it should be officially sanctioned. If not, it should be removed. -- <IXOYE><
Feb 08 2010
parent jpf <spam example.com> writes:
On 08.02.2010 20:45, BCS wrote:
 Hello JPF,
 
 Thanks for your help, I think I now understand what's going on.
 'this' is a mutable local reference in the constructor but the
 constructor automatically returns the local 'this'. This explains why
 the first case works while the second doesn't. This would also mean I
 could do "this = this(ptr);" in the second constructor and it indeed
 does work; With the above change the whole testcase works as expected.

Odd....
 I now just have to decide whether I'll use the "implementation specific
 but nice syntax" way or a static function instead of public
 constructors.

don't use implementation specific code. I suggest you file a bug/clarification request. If that is the way things are supposed to work, it should be officially sanctioned. If not, it should be removed. -- <IXOYE><

I filed a documentation bug here: http://d.puremagic.com/issues/show_bug.cgi?id=3787 Turns out there actually is a similar compiler bug: http://d.puremagic.com/issues/show_bug.cgi?id=780 that was already reported 2006 but it seems it didn't get much attention.
Feb 09 2010