On Monday, 12 March 2018 at 08:59:49 UTC, Alex wrote:
An incomplete type is perfectly ok, so there should be no problem with a pointer of the same type inside a struct. If accidentally the pointer refers "this", then it must have been set after construction. As before construction the value of "this"-pointer does not exist and after the construction the pointer to "this" has the default value of null.

Therefore, you are aware of this circumstance and appropriate movings of the pointer value are also up to you.

But I don't have a hook to update the pointer when the struct is moved. The GC may move my struct without informing me in any way. In fact, even just a copy construction will break this:

struct S {
    S* ptr;
    this(int dummy) {
        ptr = &this;
    }
    ~this() {
        // This assert will fail.
        assert(ptr == &this);
    }
}

unittest {
    S s1 = S(0);
    S s2 = S(0);

    assert(&s1 == s1.ptr);
    assert(&s2 == s2.ptr);

    s1 = s2;
}

The reason is copy construction makes a copy[1] of the lhs, then performs the copy construction[2]. If the copy construction[2] succeeds, the copy[1] is destroyed. If not, the copy[1] is blitted back over the original, to give the impression that nothing ever happened.

When the destructor is called on the copy[1], &this returns a different address from what it did before, since it's a copy and logically resides at a different address.


struct SomeType(alias fn) {}

is (or has to be) lowered to something like

struct SomeType
{
  typeof(fn)* fn;
}

Even if fn contains a frame pointer to S it is perfectly legal to have such a type. SomeType would contain a delegate then.

Indeed. But stack frames aren't copied or moved the way structs are.


However, I think, the syntax

struct S {
    int n, m;
    SomeType!(() => n + m) a;
}

is still invalid and

struct S {
    int n, m;
    auto a() { return SomeType!(() => n + m)(); }
}

has another semantics.

The latter closures above the current values inside of S.
The former has to be constructible without the context, as it is perfectly legal to write

struct Outer
{
        struct Inner{}
}

void main()
{
  auto i = Outer.Inner();
}

but would be impossible with this syntax.

I'm not using any inner structs in my examples. SomeType is assumed to be a separate type that knows nothing about S. If you're saying this should work:

unittest {
    auto tmp = typeof(S.a)();
}

It wouldn't, and such code is not possible in D today:

struct S {
    int n;
    auto a() { return SomeType!(() => n)(); }
}

struct SomeType(alias fn) {
    int get() { return fn(); }
}

unittest {
// cannot access frame pointer of foo.S.a.SomeType!(delegate () => this.n).SomeType
   auto tmp = typeof(S.a())();
}

--
  Simen

Reply via email to