Generic Property Implementation

Alex sascha.orlov at gmail.com
Mon Mar 12 10:37:00 UTC 2018


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



More information about the Digitalmars-d-learn mailing list