Thread overview
'this' in base class out contract
Jun 04, 2011
Michael Shulman
Jun 04, 2011
bearophile
Jun 04, 2011
bearophile
Jun 04, 2011
Michael Shulman
June 04, 2011
Why does the following code fail the assertion?

class A {
  void foo()
    out  { assert(stored is this); }
    body { }
}

A stored;

class B : A {
  void foo() { stored = this; }
}

void main () {
  B x = new B();
  x.foo();
}
June 04, 2011
Michael Shulman:

> Why does the following code fail the assertion?

I don't know the answer yet, but I suggest to generally compile your D code with the -w compiler switch.

I have modified the code, the __gshared and the assert removal are to simplify the asm:

import std.c.stdio: printf;

class Klass1 {
    void foo()
        out {
            printf("Klass1.this: %x\n", cast(void*)this);
            printf("Klass1.stored: %x\n", cast(void*)stored);
            //assert(stored is this);
        } body {}
}

__gshared Klass1 stored;

class Klass2 : Klass1 {
    override void foo() {
        printf("Klass2.this: %x\n", cast(void*)this);
        stored = this;
    }
}

void main () {
    Klass2 x = new Klass2();
    printf("x: %x\n", cast(void*)x);
    x.foo();
}

Output:
x: 14e2fd0
Klass2.this: 14e2fd0
Klass1.this: 41d1b0
Klass1.stored: 14e2fd0

I have compiled it with (dmd 2.053):
dmd -O


The asm:

_D4test6Klass13fooMFZv	comdat
L0:		push	EBP
		mov	EBP,ESP
		sub	ESP,018h
		mov	-018h[EBP],EAX
		call	near ptr _D9invariant12_d_invariantFC6ObjectZv
		lea	EAX,-018h[EBP]
		call	near ptr _D4test6Klass13fooMFZv8__ensureMFZv
		mov	ESP,EBP
		pop	EBP
		ret

_D4test6Klass13fooMFZv8__ensureMFZv	comdat
L0:		push	EAX
		mov	ECX,offset FLAT:_DATA
		push	dword ptr [EAX]
		push	ECX
		call	near ptr _printf
		mov	EAX,offset FLAT:_DATA[014h]
		push	dword ptr _D4test6storedC4test6Klass1
		push	EAX
		call	near ptr _printf
		add	ESP,010h
		pop	EAX
		ret

_D4test6Klass23fooMFZv	comdat
L0:		push	EBP
		mov	EBP,ESP
		sub	ESP,014h
		push	EBX
		mov	EBX,EAX
		call	near ptr _D9invariant12_d_invariantFC6ObjectZv
		mov	EAX,offset FLAT:_D4test6Klass16__vtblZ[01Ch]
		push	EBX
		push	EAX
		call	near ptr _printf
		mov	EAX,EBX
		mov	_D4test6storedC4test6Klass1,EBX
		call	near ptr _D4test6Klass13fooMFZv8__ensureMFZv
		add	ESP,8
		pop	EBX
		mov	ESP,EBP
		pop	EBP
		ret

__Dmain	comdat
L0:		push	EBX
		mov	EAX,offset FLAT:_D4test6Klass27__ClassZ
		push	EAX
		call	near ptr __d_newclass
		add	ESP,4
		mov	ECX,offset FLAT:_D4test6Klass26__vtblZ[01Ch]
		push	EAX
		mov	EBX,EAX
		push	ECX
		call	near ptr _printf
		mov	EDX,[EBX]
		mov	EAX,EBX
		call	dword ptr 018h[EDX]
		add	ESP,8
		xor	EAX,EAX
		pop	EBX
		ret

Bye,
bearophile
June 04, 2011
> x: 14e2fd0
> Klass2.this: 14e2fd0
> Klass1.this: 41d1b0
> Klass1.stored: 14e2fd0

Note how much different are the two values of the object references. They may even be in two different kinds of memory. Klass1.this may be in the static segment instead of the heap :-)

Bye,
bearophile
June 04, 2011
On Sat, Jun 4, 2011 at 4:27 AM, bearophile <bearophileHUGS@lycos.com> wrote:
>> x: 14e2fd0
>> Klass2.this: 14e2fd0
>> Klass1.this: 41d1b0
>> Klass1.stored: 14e2fd0
>
> Note how much different are the two values of the object references. They may even be in two different kinds of memory. Klass1.this may be in the static segment instead of the heap :-)

Why would that be?