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

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

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

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

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

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

July 15

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

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

July 16

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

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.