www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - can't initialize .outer in inner class

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Consider:

void fun()
{
     int x;
     class C
     {
         ...
     }
}

Objects of type C have access to x because they have an .outer 
pseudo-member.

Problem is, emplace() and any other in-situ initialization techniques 
fail (e.g. emplace() will fail with inner classes).

This seems to be a compiler issue - there's no way to initialize outer 
without calling new. What would be a proper fix to this?


Thanks,

Andrei
May 06 2015
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 05/06/2015 10:01 AM, Andrei Alexandrescu wrote:
 Consider:

 void fun()
 {
      int x;
      class C
      {
          ...
      }
 }

 Objects of type C have access to x because they have an .outer
 pseudo-member.

 Problem is, emplace() and any other in-situ initialization techniques
 fail (e.g. emplace() will fail with inner classes).

 This seems to be a compiler issue - there's no way to initialize outer
 without calling new.
The following workaround seems to do it (I didn't test it thoroughly though, in particular, I didn't test whether escape analysis always works correctly for this implementation): T nestedEmplace(T,alias x,S...)(void[] mem,S args){ auto res=cast(T)mem.ptr; enum siz=__traits(classInstanceSize, T); (cast(byte[])mem)[0..siz]=typeid(T).init[]; auto dg=(){ return x; }; res.outer=dg.ptr; static if(is(typeof(res.__ctor(args)))) res.__ctor(args); else assert(!is(typeof(&res.__ctor))&&args.length==0); return res; } void main(){ int x=12345; class C{ this(){} int foo(){ return x; } } void[__traits(classInstanceSize,C)] mem=void; auto c=nestedEmplace!(C,x)(mem); assert(c.foo()==12345); x=3; assert(c.foo()==3); }
 What would be a proper fix to this?
Probably nested types should invoke nested template instantiation, as the context pointer is runtime data. Then add a way to access the context pointer associated with some symbol (e.g. __traits).
 Thanks,

 Andrei
May 06 2015
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/6/15 3:31 AM, Timon Gehr wrote:
 On 05/06/2015 10:01 AM, Andrei Alexandrescu wrote:
 Consider:

 void fun()
 {
      int x;
      class C
      {
          ...
      }
 }

 Objects of type C have access to x because they have an .outer
 pseudo-member.

 Problem is, emplace() and any other in-situ initialization techniques
 fail (e.g. emplace() will fail with inner classes).

 This seems to be a compiler issue - there's no way to initialize outer
 without calling new.
The following workaround seems to do it (I didn't test it thoroughly though, in particular, I didn't test whether escape analysis always works correctly for this implementation): T nestedEmplace(T,alias x,S...)(void[] mem,S args){ auto res=cast(T)mem.ptr; enum siz=__traits(classInstanceSize, T); (cast(byte[])mem)[0..siz]=typeid(T).init[]; auto dg=(){ return x; }; res.outer=dg.ptr; static if(is(typeof(res.__ctor(args)))) res.__ctor(args); else assert(!is(typeof(&res.__ctor))&&args.length==0); return res; } void main(){ int x=12345; class C{ this(){} int foo(){ return x; } } void[__traits(classInstanceSize,C)] mem=void; auto c=nestedEmplace!(C,x)(mem); assert(c.foo()==12345); x=3; assert(c.foo()==3); }
Thanks, that's quite the tour de force. I tried to massage things in various places to avoid changing emplace()'s signature, no avail. I think we have a problem here. -- Andrei
May 06 2015
prev sibling parent Kenji Hara via Digitalmars-d <digitalmars-d puremagic.com> writes:
2015/05/06 19:35 "Timon Gehr via Digitalmars-d" <digitalmars-d puremagic.com
:

 Probably nested types should invoke nested template instantiation, as the
context pointer is runtime data. Then add a way to access the context pointer associated with some symbol (e.g. __traits). Related: https://issues.dlang.org/show_bug.cgi?id=8863 Kenji Hara
May 06 2015