Jump to page: 1 2 3
Thread overview
static foreach considered
Jun 08, 2015
Idan Arye
Jun 08, 2015
Jonathan M Davis
Jun 08, 2015
Idan Arye
Jun 08, 2015
Timon Gehr
Jun 08, 2015
Idan Arye
Jun 08, 2015
Timon Gehr
Jun 08, 2015
Idan Arye
Jun 08, 2015
Tofu Ninja
Jun 08, 2015
Timon Gehr
Jun 09, 2015
Marc Schütz
Identifier from string - Re: static foreach considered
May 14, 2018
Nick Treleaven
Jun 08, 2015
Daniel N
Jun 08, 2015
rsw0x
Jun 09, 2015
Idan Arye
Jun 09, 2015
rsw0x
Jun 09, 2015
Idan Arye
Jun 08, 2015
Artur Skawina
Jun 09, 2015
Dicebot
Jun 16, 2015
Daniel N
Jun 16, 2015
Daniel N
Jun 17, 2015
Daniel N
Jun 16, 2015
jmh530
June 08, 2015
Walter and I are looking at ways to implement it. Here's a baseline without static foreach - a "trace" function that prints function calls before they are made:

http://dpaste.dzfl.pl/762c83c7fe30

If the function is overloaded, that won't work. In such cases, static foreach might be helpful. Here's code from the cycle "I have a dream":

http://dpaste.dzfl.pl/82a70c809210

I'm trying to collect together motivating examples and to figure out the semantics of the feature.


Andrei

June 08, 2015
On Monday, 8 June 2015 at 20:02:11 UTC, Andrei Alexandrescu wrote:
> Walter and I are looking at ways to implement it. Here's a baseline without static foreach - a "trace" function that prints function calls before they are made:
>
> http://dpaste.dzfl.pl/762c83c7fe30
>
> If the function is overloaded, that won't work. In such cases, static foreach might be helpful. Here's code from the cycle "I have a dream":
>
> http://dpaste.dzfl.pl/82a70c809210
>
> I'm trying to collect together motivating examples and to figure out the semantics of the feature.
>
>
> Andrei

How will scoping work? Similar to mixin templates?

It would be nice together with this feature to be able to mixin identifiers:

    static foreach (ident; ["foo", "bar"])
    {
        auto mixin(ident)()
        {
            // code for foo/bar
        }
    }

Otherwise, other than overloads and template instantiations this won't be much better then generating code strings with CTFE...
June 08, 2015
On Monday, 8 June 2015 at 20:16:53 UTC, Idan Arye wrote:
> On Monday, 8 June 2015 at 20:02:11 UTC, Andrei Alexandrescu wrote:
>> Walter and I are looking at ways to implement it. Here's a baseline without static foreach - a "trace" function that prints function calls before they are made:
>>
>> http://dpaste.dzfl.pl/762c83c7fe30
>>
>> If the function is overloaded, that won't work. In such cases, static foreach might be helpful. Here's code from the cycle "I have a dream":
>>
>> http://dpaste.dzfl.pl/82a70c809210
>>
>> I'm trying to collect together motivating examples and to figure out the semantics of the feature.
>>
>>
>> Andrei
>
> How will scoping work? Similar to mixin templates?
>
> It would be nice together with this feature to be able to mixin identifiers:
>
>     static foreach (ident; ["foo", "bar"])
>     {
>         auto mixin(ident)()
>         {
>             // code for foo/bar
>         }
>     }
>
> Otherwise, other than overloads and template instantiations this won't be much better then generating code strings with CTFE...

I would assume that it would be pretty much the same as doing

foreach(T; TypeTuple!(...))
{
    ...
}

except that you're not forced to shove everything in a TypeTuple.

- Jonathan M Davis
June 08, 2015
On 06/08/2015 10:16 PM, Idan Arye wrote:
> On Monday, 8 June 2015 at 20:02:11 UTC, Andrei Alexandrescu wrote:
>> Walter and I are looking at ways to implement it. Here's a baseline
>> without static foreach - a "trace" function that prints function calls
>> before they are made:
>>
>> http://dpaste.dzfl.pl/762c83c7fe30
>>
>> If the function is overloaded, that won't work. In such cases, static
>> foreach might be helpful. Here's code from the cycle "I have a dream":
>>
>> http://dpaste.dzfl.pl/82a70c809210
>>
>> I'm trying to collect together motivating examples and to figure out
>> the semantics of the feature.
>>
>>
>> Andrei
>
> How will scoping work? Similar to mixin templates?
> ...

I think the body should have access to a scope that is hidden from the outside which contains the loop variable, but declarations should be inserted into the enclosing scope like for static if.

> It would be nice together with this feature to be able to mixin
> identifiers:
>
>      static foreach (ident; ["foo", "bar"])
>      {
>          auto mixin(ident)()
>          {
>              // code for foo/bar
>          }
>      }
>
> Otherwise, other than overloads and template instantiations this won't
> be much better then generating code strings with CTFE...

+1. Other use cases:

auto mixin(ident) = x;

identifier.list.mixin(ident).foo();

import std.mixin(ident);

June 08, 2015
On Monday, 8 June 2015 at 20:02:11 UTC, Andrei Alexandrescu wrote:
> I'm trying to collect together motivating examples and to figure out the semantics of the feature.
>
>
> Andrei

Hmmm, codegen based on UDA?

struct magic
{
  interface readonly;

  private static struct hidden
  {
    @readonly enum a = 0;
  }
  static foreach(id; __traits(allMembers, hidden))
  {
    // Inspect UDA and generate code accordingly,
    // Ex fields with public ReadOnly and private ReadWrite
  }
}
June 08, 2015
On Monday, 8 June 2015 at 21:14:46 UTC, Jonathan M Davis wrote:
> I would assume that it would be pretty much the same as doing
>
> foreach(T; TypeTuple!(...))
> {
>     ...
> }
>
> except that you're not forced to shove everything in a TypeTuple.
>
> - Jonathan M Davis

If that was the case, A library solution for converting a compile-time range to a TypeTuple would have sufficed(http://dpaste.dzfl.pl/7eb30f5e1156 - this compiles in 2.67).

The problem with regular `foreach` over type tuple is that declarations inside the foreach's body are invisible from the outside. If `static foreach` had this limitation, Andrei's example wouldn't work since `trace` would be local to the body of the `static foreach`. This essentially renders the main usecase of this feature(declaring stuff) and leaves us with a loop unrolling optimization...
June 08, 2015
On Monday, 8 June 2015 at 21:32:52 UTC, Timon Gehr wrote:
> I think the body should have access to a scope that is hidden from the outside which contains the loop variable, but declarations should be inserted into the enclosing scope like for static if.

This would require some syntax to mark the declarations we want to expose. Maybe `out`?

This is far better than the mixin template approach, since it'll alert us early about conflicts:

    static foreach (ident; ["a", "b", "a"])
    {
        int mixin(ident ~ "1");
        out int mixin(ident ~ "2");
    }

`a1` is created twice, but that's OK since it isn't marked with `out`. `a2` is declared twice and raises a compilation error because it's marked with `out`. This will ensure these kind of errors are detected early and the compilation error points to the exact place of declaration.
June 08, 2015
On Monday, 8 June 2015 at 20:02:11 UTC, Andrei Alexandrescu wrote:
> I'm trying to collect together motivating examples and to figure out the semantics of the feature.

maybe not completely related, but I made a blog post on using CTFE to unroll foreach at compiletime

https://rsw0x.github.io/post/switch-unrolling/

I find myself often writing recursive templates for compile-time generation of constructs that could be done cleaner with static foreach.
June 08, 2015
On 06/09/2015 12:12 AM, Idan Arye wrote:
> On Monday, 8 June 2015 at 21:32:52 UTC, Timon Gehr wrote:
>> I think the body should have access to a scope that is hidden from the
>> outside which contains the loop variable, but declarations should be
>> inserted into the enclosing scope like for static if.
>
> This would require some syntax to mark the declarations we want to
> expose. Maybe `out`?
>
> This is far better than the mixin template approach, since it'll alert
> us early about conflicts:
>
>      static foreach (ident; ["a", "b", "a"])
>      {
>          int mixin(ident ~ "1");
>          out int mixin(ident ~ "2");
>      }
>
> `a1` is created twice, but that's OK since it isn't marked with `out`.
> `a2` is declared twice and raises a compilation error because it's
> marked with `out`. This will ensure these kind of errors are detected
> early and the compilation error points to the exact place of declaration.

I actually intended all declarations in the body to be inserted into the enclosing scope, at least by default.
June 08, 2015
On 6/8/15 2:14 PM, Jonathan M Davis wrote:
>
> I would assume that it would be pretty much the same as doing
>
> foreach(T; TypeTuple!(...))
> {
>      ...
> }
>
> except that you're not forced to shove everything in a TypeTuple.

I'm even fine with the type tuple, just allow at declaration level and don't introduce a scope. Would be a great start. -- Andrei
« First   ‹ Prev
1 2 3