Thread overview
Dollar identifiers in code-generating constructs
Jul 03, 2024
Quirin Schroll
Jul 03, 2024
monkyyy
Jul 04, 2024
Quirin Schroll
Jul 04, 2024
monkyyy
Jul 04, 2024
Quirin Schroll
Jul 15, 2024
Meta
Jul 16, 2024
Quirin Schroll
Jul 16, 2024
ryuukk_
Jul 16, 2024
Quirin Schroll
July 03, 2024

A dollar identifier is an Identifier with a $ at the end. In a code-generating construct (mixed-in mixin template and static foreach/static foreach_reverse) the $ is replaced by a number.

For a loop, it is the index of iteration.

For a mixin template, it is the number of mixin templates mixed in up until this point.


Example: loop

enum xs = ["A", "BC", "DEF"];
static foreach (x; xs)
{
    size_t l = x.length; // Error on "BC" and "DEF", already defined.
}
enum xs = ["A", "BC", "DEF"];
static foreach (x; xs)
{
    size_t l$ = x.length; // Good: becomes `l0`, `l1`, `l2`
}

Example: mixin template

mixin template mixMeIn(T)
{
    alias R = int delegate(T);
}

struct S
{
    mixin mixMeIn!int; // Okay
    mixin mixMeIn!int; // Error, `R` already defined
}
mixin template mixMeIn(T)
{
    alias R$ = int delegate(T);
}

struct S
{
    mixin mixMeIn!int; // Okay, defines `R0`
    mixin mixMeIn!int; // Okay, defines `R1`
}
July 03, 2024

On Wednesday, 3 July 2024 at 10:25:14 UTC, Quirin Schroll wrote:

>

A dollar identifier is an Identifier with a $ at the end. In a code-generating construct (mixed-in mixin template and static foreach/static foreach_reverse) the $ is replaced by a number.

[...]

is there a static foreach usecase where you cant use a index?

template innate(T,alias discirmintor){
  T innate;
}
static foreach(i,A;...){
  alias L(int i_:i)=innate(F!A,i);
}
July 04, 2024

On Wednesday, 3 July 2024 at 13:34:11 UTC, monkyyy wrote:

>

On Wednesday, 3 July 2024 at 10:25:14 UTC, Quirin Schroll wrote:

>

A dollar identifier is an Identifier with a $ at the end. In a code-generating construct (mixed-in mixin template and static foreach/static foreach_reverse) the $ is replaced by a number.

[...]

is there a static foreach usecase where you cant use a index?

template innate(T,alias discirmintor){
  T innate;
}
static foreach(i,A;...){
  alias L(int i_:i)=innate(F!A,i);
}

One can always use the index: mixin("size_t l", cast(int)i, " = ..."). This is a lot of boilerplate for something conceptually simple.

July 04, 2024

On Thursday, 4 July 2024 at 11:13:47 UTC, Quirin Schroll wrote:

>

On Wednesday, 3 July 2024 at 13:34:11 UTC, monkyyy wrote:

>

On Wednesday, 3 July 2024 at 10:25:14 UTC, Quirin Schroll wrote:

>

A dollar identifier is an Identifier with a $ at the end. In a code-generating construct (mixed-in mixin template and static foreach/static foreach_reverse) the $ is replaced by a number.

[...]

is there a static foreach usecase where you cant use a index?

template innate(T,alias discirmintor){
  T innate;
}
static foreach(i,A;...){
  alias L(int i_:i)=innate(F!A,i);
}

One can always use the index: mixin("size_t l", cast(int)i, " = ..."). This is a lot of boilerplate for something conceptually simple.

I think you can always also use template specialization and it should be faster to access then mixins and theres a handful of other benefits should as being able to pass them around as an overloadset

July 04, 2024

Maybe this isn’t worth it, as mixin Identifiers would supersede this.

July 15, 2024

On Wednesday, 3 July 2024 at 10:25:14 UTC, Quirin Schroll wrote:

>

A dollar identifier is an Identifier with a $ at the end. In a code-generating construct (mixed-in mixin template and static foreach/static foreach_reverse) the $ is replaced by a number.

For a loop, it is the index of iteration.

For a mixin template, it is the number of mixin templates mixed in up until this point.


Example: loop

enum xs = ["A", "BC", "DEF"];
static foreach (x; xs)
{
    size_t l = x.length; // Error on "BC" and "DEF", already defined.
}
enum xs = ["A", "BC", "DEF"];
static foreach (x; xs)
{
    size_t l$ = x.length; // Good: becomes `l0`, `l1`, `l2`
}

Example: mixin template

mixin template mixMeIn(T)
{
    alias R = int delegate(T);
}

struct S
{
    mixin mixMeIn!int; // Okay
    mixin mixMeIn!int; // Error, `R` already defined
}
mixin template mixMeIn(T)
{
    alias R$ = int delegate(T);
}

struct S
{
    mixin mixMeIn!int; // Okay, defines `R0`
    mixin mixMeIn!int; // Okay, defines `R1`
}

This is very similar to a proposal by Timon Gehr to add __local variables that are local to static foreach bodies:
https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1010.md#local-declarations

July 16, 2024

Good idea, but bad syntax, besides, it'll be confusing with https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1039.md

July 16, 2024

On Tuesday, 16 July 2024 at 07:03:43 UTC, ryuukk_ wrote:

>

Good idea, but bad syntax, besides, it'll be confusing with https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1039.md

How it’ll be confusing? The syntax is very different having the dollar in brackets and on the identifier.

July 16, 2024

On Monday, 15 July 2024 at 17:50:10 UTC, Meta wrote:

>

On Wednesday, 3 July 2024 at 10:25:14 UTC, Quirin Schroll wrote:

>

A dollar identifier is an Identifier with a $ at the end. In a code-generating construct (mixed-in mixin template and static foreach/static foreach_reverse) the $ is replaced by a number.

For a loop, it is the index of iteration.

For a mixin template, it is the number of mixin templates mixed in up until this point.


Example: loop

enum xs = ["A", "BC", "DEF"];
static foreach (x; xs)
{
    size_t l = x.length; // Error on "BC" and "DEF", already defined.
}
enum xs = ["A", "BC", "DEF"];
static foreach (x; xs)
{
    size_t l$ = x.length; // Good: becomes `l0`, `l1`, `l2`
}

Example: mixin template

mixin template mixMeIn(T)
{
    alias R = int delegate(T);
}

struct S
{
    mixin mixMeIn!int; // Okay
    mixin mixMeIn!int; // Error, `R` already defined
}
mixin template mixMeIn(T)
{
    alias R$ = int delegate(T);
}

struct S
{
    mixin mixMeIn!int; // Okay, defines `R0`
    mixin mixMeIn!int; // Okay, defines `R1`
}

This is very similar to a proposal by Timon Gehr to add __local variables that are local to static foreach bodies:
https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1010.md#local-declarations

It’s different because my symbols aren’t local. Even if both features could be used for the same end, they end up being quite different. What you do with R0, R1, etc. is up to you. They’re visible and have predictable names. If you define R0 elsewhere, the names clash. __local on the other hand would hide the symbols outside the loop/template. Whether you want a simple mechanism to generate predictable different names or make symbols basically private is up to your use case.