On Monday, 12 March 2018 at 09:54:20 UTC, Simen Kjærås wrote:
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.
Sure, you have.
https://dlang.org/spec/struct.html#assign-overload
Point #4.
In this case,
ref S opAssign(ref S rhs)
{
return this;
}
Another point is, that I hope, that pointers don't move anywhere,
as in C, by definition.
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.
Yes. This is how the structs are meant to be, I thought :)
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:
Ah... I was unclear, I think...
unittest {
auto tmp = typeof(S.a)();
}
I thought, this shouldn't be possible (at least in my mind)
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(); }
}
But this is clearly valid.
unittest {
// cannot access frame pointer of foo.S.a.SomeType!(delegate
() => this.n).SomeType
auto tmp = typeof(S.a())();
}
For sure, tmp cannot be defined without an instance of S. So the
correct unittest in my eyes would be:
unittest {
S s;
auto res = s.a;
assert(res.get == S.init.n);
}
--
Simen