potential behavior of nested structs

Era Scarecrow rtcvb32 at yahoo.com
Sun Feb 3 16:26:09 PST 2013


  Branched off since this seems appropriate.

  Currently nested structs are illegal, since having them on the 
stack passing them with a context pointer would result in illegal 
code or undefined behavior.

   struct Outer {
     struct Inner {
       string innerString;
       string getOuterString() { return outerString; }
     }

     string outerString;
     Inner innerInstance;
   }

   auto func(Outer x) {
     return x.innerInstance;
   }

   //inner needs outer instance, is not immediately usable.
   Outer.Inner inner;
   Outer outer;

   //points to temporary 'x' from func, likely garbage
   inner = func(outer);


  If Outer had been a class, then being on the heap the problem 
goes away, plus the class is always by reference.

  Considering behavior for making nested structs legal, it would 
require a few extra rules to ensure it would be safe to use.

  1) It cannot return a nested struct outside of it's level of 
control where it can ensure it exists. Alternatively returning a 
nested struct (outside of it's own implementation) could be 
downright illegal, but that seems too limiting.

   //error, x is a temporary
   Inner func(Outer x){return x.innerInstance; }

   //Inner still valid after call.
   Inner func(ref Outer x){return x.innerInstance; }

  2) Nested structs need context pointers, however with being able 
to swap structs at a whim having an address as part of the 
struct's contents is impractical. In this case the structs being 
passed has to silently pass in the function call the related 
pointers. If it's nested multiple levels, each level would have 
to be referenced.  If you don't/can't return it outside a 
function receiving it (or it's parent), then it's as safe as ref 
is.

   struct Outer {
     struct Inner {}
     void func(Inner x) {}

//translates to
     void func(ref Outer this, ref Outer xPtr, Inner x) {}
   }

  3) If the nested struct has no data then it's more a name-space 
for behavior (and an alias for the outer/parent struct). If the 
nested struct does not actually use it's parents data in any 
methods, then it can in turn be copied/returned without any extra 
context pointers.

  4) Nested structs's may rely on their parent's data, but the 
parents don't have to rely on the nested struct's data (If they 
do, then opAssign would be needed, or postblit to handle the 
changes). An example of this is potentially in a DB environment 
where a struct holding a text query can be replaced by a compiled 
version of that query, the parent doesn't need to know.

   struct Dog {
     string dogName;
     struct Tail {
       string colorOf = "Black"; //just data.
       string name() { return dogName; }
     }
     Tail tail;

     void func(ref Dog rhs) {
       //tail2 retains context pointer to rhs.
       Tail tail2 = rhs.tail;

       writeln(tail.name());   //Scruffy
       writeln(tail2.name());  //Spike
     }

     //ref, otherwise illegal to return
     Tail doesSomething(ref Outer rhs) {
       return rhs.tail;
     }
   }

   Dog dog1 = Dog("Scruffy");
   Dog dog2 = Dog("Spike"); dog2.tail.colorOf = "White";

   dog1.func(dog2);

   //context pointer to dog2 thrown away after copy,
   //unless opAssign declared and does something.
   //so dog1's tail belongs to dog1, not dog2
   dog1.tail = dog2.tail;

   assert(dog1.dogName == "Scruffy");     //untouched
   assert(dog1.tail.name == "Scruffy");   //dog1 owns tail, not 
dog2
   assert(dog1.tail.colorOf == "White");  //data copied for tail.


  Thoughts and ideas?


More information about the Digitalmars-d mailing list