Generic Property Implementation

Alex sascha.orlov at gmail.com
Mon Mar 12 08:59:49 UTC 2018


On Monday, 12 March 2018 at 07:04:19 UTC, Simen Kjærås wrote:
> On Saturday, 10 March 2018 at 17:43:06 UTC, Simen Kjærås wrote:
>> I'm not sure how fixable this is, but I am sure that there's 
>> plenty of benefit to being able to write code like this:
>>
>> struct S {
>>     int n, m;
>>     SomeType!(() => n + m) a;
>> }
>>
>> over this:
>>
>> struct S {
>>     int n, m;
>>     auto a() { return SomeType!(() => n + m)(); }
>> }
>>
>> Anyways, I filed a bug for it:
>> https://issues.dlang.org/show_bug.cgi?id=18587
>
> Actually, this is not fixable. If we consider for a moment the 
> internals of SomeType in the above code, it's something like 
> this:
>
> struct SomeType(alias fn) {
>     S* context;
> }
>
> The full layout of S then becomes this:
>
> struct S {
>     int n;
>     int m;
>     S* a.context; // points to 'this'.
> }
>
> Since structs in D are defined to be movable by blitting only, 
> with no cleanup afterwards, internal pointers are a no-no. Ref 
> https://dlang.org/spec/garbage.html:
>
>> Do not have pointers in a struct instance that point back to 
>> the same instance. The trouble with this is if the instance 
>> gets moved in memory, the pointer will point back to where it 
>> came from, with likely disastrous results.
>
> One possible solution would be for the above code to generate 
> the function a() instead of making 'a' a member. This has its 
> own set of issues, though - suddenly something that looks like 
> a member isn't one, and its address can't be taken, it can't be 
> passed by ref, etc.
>
> --
>   Simen

This is strange...

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.

On the other side:

Isn't it the case, that

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.

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.


More information about the Digitalmars-d-learn mailing list