www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Mutually recursive template expansion

reply Stephen <stephen.personal27 gmail.com> writes:
I've been trying out templates in more depth and one thing I was 
wondering was whether template expansions with circular 
dependencies might work.
Here is an example that doesn't work:
```d
mixin(A!());
mixin(B!());

void main() {}

template A() {
     const char[] A = q{
         struct Ar {
             Br b;
         }
     };
}

template B() {
     const char[] B = q{
         struct Br {
             Ar a;
         }
     };
}
```
This code should work should mutual recursion be supported. How 
might I get it to work properly (without sacrificing recursion or 
templates)?
Oct 01 2021
next sibling parent reply jfondren <julian.fondren gmail.com> writes:
On Friday, 1 October 2021 at 14:03:06 UTC, Stephen wrote:
 This code should work should mutual recursion be supported.
It still wouldn't work, because structs are value types and it's impossible to say how large either struct is: Error: struct `mutualrec.Ar` no size because of forward reference With s/struct/class/ it still wouldn't work because this is a mixin problem rather than a problem of template mutual recursion: ```d mixin(q{ class Ar { Br b; } }); mixin(q{ class Br { Ar b; } }); ``` mutualrec2.d-mixin-1(1): Error: undefined identifier `Br`, did you mean class `Ar`? This seems like a surprising limitation of mixin, though, which isn't highlighted by the spec.
Oct 01 2021
next sibling parent reply Stephen <stephen.personal27 gmail.com> writes:
On Friday, 1 October 2021 at 14:26:39 UTC, jfondren wrote:
 On Friday, 1 October 2021 at 14:03:06 UTC, Stephen wrote:
 This code should work should mutual recursion be supported.
It still wouldn't work, because structs are value types and it's impossible to say how large either struct is: Error: struct `mutualrec.Ar` no size because of forward reference With s/struct/class/ it still wouldn't work because this is a mixin problem rather than a problem of template mutual recursion: ```d mixin(q{ class Ar { Br b; } }); mixin(q{ class Br { Ar b; } }); ``` mutualrec2.d-mixin-1(1): Error: undefined identifier `Br`, did you mean class `Ar`? This seems like a surprising limitation of mixin, though, which isn't highlighted by the spec.
All right I'll try to design without mutual recursion but mixins don't seem to work if they're put out of order. (i.e. this works: ```d struct Ar { Br b; ubyte a; } struct Br { ubyte b; } ``` but not this: ```d mixin(q{struct Ar { Br b; ubyte a; }}); mixin(q{struct Br { ubyte b; }}); ``` ). Is this by design?
Oct 02 2021
parent Basile B. <b2.temp gmx.com> writes:
On Saturday, 2 October 2021 at 08:48:24 UTC, Stephen wrote:
 Is this by design?
No but it's easily explainable. ```d struct Ar { Br b; ubyte a; } struct Br { ubyte b; } ``` `Ar` semantic starts, members are analyzed, that begins with the variable declaration `Br b`. `Br` type needs to be resolved. `Br` can be found in the AST as it is declared manually. Now `Br` is run and finally `Ar` sema continues. ```d mixin(q{struct Ar { Br b; ubyte a; }}); mixin(q{struct Br { ubyte b; }}); ``` The first mixin is compiled (`compileIt()` in dmd code base). The AST is now the same as obtained by parsing ```d struct Ar { Br b; ubyte a; } mixin(q{struct Br { ubyte b; }}); ``` `Ar` semantic starts, members are analyzed, that begins with the variable declaration`Br b`. But `Br` cannot be resolved because **it is not yet in the AST** and the symbol tables.
Oct 02 2021
prev sibling parent reply bauss <jj_1337 live.dk> writes:
On Friday, 1 October 2021 at 14:26:39 UTC, jfondren wrote:
 On Friday, 1 October 2021 at 14:03:06 UTC, Stephen wrote:
 This code should work should mutual recursion be supported.
It still wouldn't work, because structs are value types and it's impossible to say how large either struct is: Error: struct `mutualrec.Ar` no size because of forward reference With s/struct/class/ it still wouldn't work because this is a mixin problem rather than a problem of template mutual recursion: ```d mixin(q{ class Ar { Br b; } }); mixin(q{ class Br { Ar b; } }); ``` mutualrec2.d-mixin-1(1): Error: undefined identifier `Br`, did you mean class `Ar`? This seems like a surprising limitation of mixin, though, which isn't highlighted by the spec.
Actually it is covered by the spec. See: https://dlang.org/spec/expression.html#mixin_expressions It clearly says: ``` Each AssignExpression in the ArgumentList is evaluated at compile time ``` Which means that Br cannot be used in Ar since it cannot be evaluated at compile time during the mixin of Ar.
Oct 04 2021
parent Paul Backus <snarwin gmail.com> writes:
On Monday, 4 October 2021 at 11:38:04 UTC, bauss wrote:
 Actually it is covered by the spec.

 See:

 https://dlang.org/spec/expression.html#mixin_expressions

 It clearly says:

 ```
 Each AssignExpression in the ArgumentList is evaluated at 
 compile time
 ```

 Which means that Br cannot be used in Ar since it cannot be 
 evaluated at compile time during the mixin of Ar.
That's not what that sentence means. Here's the full version, without the part you cut off:
 Each AssignExpression in the ArgumentList is evaluated at 
 compile time, and the result must be representable as a string. 
 The resulting strings are concatenated to form a string. The 
 text contents of the string must be compilable as a valid 
 Expression, and is compiled as such.
In other words: the string being mixed in is what's evaluated at compile-time. The code *inside* the string is treated the same way as any other code.
Oct 04 2021
prev sibling parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Friday, 1 October 2021 at 14:03:06 UTC, Stephen wrote:
 I've been trying out templates in more depth and one thing I 
 was wondering was whether template expansions with circular 
 dependencies might work.
 Here is an example that doesn't work:
 ```d
 mixin(A!());
 mixin(B!());

 void main() {}

 template A() {
     const char[] A = q{
         struct Ar {
             Br b;
         }
     };
 }

 template B() {
     const char[] B = q{
         struct Br {
             Ar a;
         }
     };
 }
 ```
 This code should work should mutual recursion be supported. How 
 might I get it to work properly (without sacrificing recursion 
 or templates)?
Just curious since I haven't found a use case for this myself, what's the benefit rather than having a separate struct?
Oct 02 2021