digitalmars.D.learn - Cannot use std.array.Appender in recursive types
- =?UTF-8?B?Tm9yZGzDtnc=?= (28/28) Aug 09 2017 Why doesn't appending to `subs` work with std.array.Appender in
- Steven Schveighoffer (24/55) Aug 09 2017 Here is the problem:
- Timon Gehr (25/89) Aug 09 2017 It's a forward reference bug. Self-contained test case:
- =?UTF-8?B?Tm9yZGzDtnc=?= (3/6) Aug 09 2017 If Phobos compiles with the change would that change deserve a PR?
- Steven Schveighoffer (7/13) Aug 09 2017 I'm pretty sure it will fail in cases where front is a non-@property
Why doesn't appending to `subs` work with std.array.Appender in struct T { string src; import std.array : Appender; Appender!(T[]) subs; } T t; t.subs ~= T.init; // ERRORS t.subs.put(T.init); // ERRORS when it works with builtin arrays as in struct S { string src; S[] subs; } S s; s.subs ~= S.init; ? Specifically t.subs ~= T.init errors as Error: cannot append type T to type Appender!(T[]) and t.subs.put(T.init); errors as Error: template std.array.Appender!(T[]).Appender.put cannot deduce function from argument types !()(T), candidates are:
Aug 09 2017
On 8/9/17 2:25 PM, Nordlöw wrote:Why doesn't appending to `subs` work with std.array.Appender in struct T { string src; import std.array : Appender; Appender!(T[]) subs; } T t; t.subs ~= T.init; // ERRORS t.subs.put(T.init); // ERRORS when it works with builtin arrays as in struct S { string src; S[] subs; } S s; s.subs ~= S.init; ? Specifically t.subs ~= T.init errors as Error: cannot append type T to type Appender!(T[])Here is the problem: ElementType!(T[]) is void. Here is ElementType: template ElementType(R) { static if (is(typeof(R.init.front.init) T)) alias ElementType = T; else alias ElementType = void; } So what is happening here (I think), is that T isn't fully defined, so T.init.front.init is an error at this point. Therefore the else clause is selected. This is one of the problems with using is(typeof) (or __traits(compiles)) with an "else" clause. You may not be checking what you think you are checking, and end up with the wrong result. So essentially, Appender!(T[]) inside a T becomes (essentially) Appender!(void[]). And you can't append a T to a void[]. If I change the definition of ElementType to use R.init.front instead of R.init.front.init, it compiles. But I'm pretty sure this will break other ranges. Somewhere, there's an answer. -Steve
Aug 09 2017
On 09.08.2017 21:00, Steven Schveighoffer wrote:On 8/9/17 2:25 PM, Nordlöw wrote:It's a forward reference bug. Self-contained test case: auto front(T)(T[] a){ return a[0]; } template ElementType(R){ pragma(msg, typeof(R.init.front)); /* Error: struct bug.T no size because of forward reference */ static if (is(typeof(R.init.front) T)) alias ElementType = T; else alias ElementType = void; } struct Appender(A){ A a; alias T=ElementType!A; private enum canPutItem(U)=is(U==T); void put(T)(T t)if(canPutItem!T){ a~=t; } } struct T{ string src; Appender!(T[]) subs; } void main(){ T t; t.subs.put(T.init); }Why doesn't appending to `subs` work with std.array.Appender in struct T { string src; import std.array : Appender; Appender!(T[]) subs; } T t; t.subs ~= T.init; // ERRORS t.subs.put(T.init); // ERRORS when it works with builtin arrays as in struct S { string src; S[] subs; } S s; s.subs ~= S.init; ? Specifically t.subs ~= T.init errors as Error: cannot append type T to type Appender!(T[])Here is the problem: ElementType!(T[]) is void. Here is ElementType: template ElementType(R) { static if (is(typeof(R.init.front.init) T)) alias ElementType = T; else alias ElementType = void; } So what is happening here (I think), is that T isn't fully defined, so T.init.front.init is an error at this point. Therefore the else clause is selected. This is one of the problems with using is(typeof) (or __traits(compiles)) with an "else" clause. You may not be checking what you think you are checking, and end up with the wrong result. So essentially, Appender!(T[]) inside a T becomes (essentially) Appender!(void[]). And you can't append a T to a void[]. If I change the definition of ElementType to use R.init.front instead of R.init.front.init, it compiles. But I'm pretty sure this will break other ranges. Somewhere, there's an answer. -Steve
Aug 09 2017
On Wednesday, 9 August 2017 at 19:00:54 UTC, Steven Schveighoffer wrote:If I change the definition of ElementType to use R.init.front instead of R.init.front.init, it compiles. But I'm pretty sure this will break other ranges.If Phobos compiles with the change would that change deserve a PR?
Aug 09 2017
On 8/9/17 6:24 PM, Nordlöw wrote:On Wednesday, 9 August 2017 at 19:00:54 UTC, Steven Schveighoffer wrote:I'm pretty sure it will fail in cases where front is a non- property function. I think in terms of Timon's post, he is doing what I did, and it's not working. I think it's a forward reference bug, and that just needs to be fixed. -SteveIf I change the definition of ElementType to use R.init.front instead of R.init.front.init, it compiles. But I'm pretty sure this will break other ranges.If Phobos compiles with the change would that change deserve a PR?
Aug 09 2017