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?

Reply via email to