Thread overview
foreach vs static foreach on compile time tuples
Aug 26
monkyyy
Aug 27
monkyyy
August 24

Which are the pros and cons of foreach vs static foreach on a compile time tuple in D in terms of compiler performance and resource usage? Does static foreach generate more ast duplications?

August 24

On Sunday, 24 August 2025 at 08:35:57 UTC, Per Nordlöw wrote:

>

Which are the pros and cons of foreach vs static foreach on a compile time tuple in D in terms of compiler performance and resource usage? Does static foreach generate more ast duplications?

--
Yes, it will make the compile-time longer, but usually you can ignore.
If you don't have static foreach(int i;0..99999999),you are no need to worry about it.

August 26
On Sunday, August 24, 2025 2:35:57 AM Mountain Daylight Time Per Nordlöw via Digitalmars-d-learn wrote:
> Which are the pros and cons of foreach vs static foreach on a compile time tuple in D in terms of compiler performance and resource usage? Does static foreach generate more ast duplications?

As I understand it, there should be no real difference in compile time performance between static foreach and a foreach being done at compile time. The main differences are that foreach introduces a new scope (whereas static foreach does not), that static foreach _must_ be done at compile time (whereas whether foreach is done at compile time depends on what you're iterating over), and that static foreach can be used in some contexts where foreach isn't legal (e.g. at module scope).

So, if you're iterating over something like an AliasSeq within a function body, it really shouldn't matter which you use.

- Jonathan M Davis




August 26
On Sunday, August 24, 2025 6:30:08 AM Mountain Daylight Time David T. Oxygen via Digitalmars-d-learn wrote:
> On Sunday, 24 August 2025 at 08:35:57 UTC, Per Nordlöw wrote:
> > Which are the pros and cons of foreach vs static foreach on a compile time tuple in D in terms of compiler performance and resource usage? Does static foreach generate more ast duplications?
>
> --
> Yes, it will make the compile-time longer, but usually you can
> ignore.
> If you don't have `static foreach(int i;0..99999999)`,you are no
> need to worry about it.

You misunderstood the question. He was asking whether the performance between foreach and static foreach differs when what's being iterated over is a compile-time construct which therefore must be iterated at compile time. And in such a sitation, the performance should be identical (or so close that you couldn't tell the difference).

On the other hand,

foreach(i; 0 .. 10_000)
{...}

and

static foreach(i; 0 .. 10_000)
{{...}}

are completely different from one another, because the foreach would iterate at runtime, whereas the static foreach would iterate at compile time, because the arguments to foreach are not compile-time arguments.

In contrast,

foreach(i; AliasSeq!(1, 2, 3, 4, 5))
{...}

static foreach(i; AliasSeq!(1, 2, 3, 4, 5))
{{...}}

would both run at compile time, because AliasSeq is a compile-time construct and must be evaluated at compile time.

- Jonathan M Davis




August 26

On Sunday, 24 August 2025 at 08:35:57 UTC, Per Nordlöw wrote:

>

Which are the pros and cons of foreach vs static foreach on a compile time tuple in D in terms of compiler performance and resource usage? Does static foreach generate more ast duplications?

Since enum foreach is being deleted and nore properly implimented (ugh that not why I report bugs; to remove features) I believe in practice both should be O(n) but there isnt a way to generate a alias foreach lazily, it will exist in memory so it must allocate O(n)

I would predict that alias foreach will be 2x slower until your ram is filled at a point 1/2 the size of static foreach(at which point a new curve gets introduced) which swap being worse then ram skyrockets, then shortly after static foreach joins in.


#!opend -unittest -main -run app.d
bool isEvenImpl(int I)()=>! I%2;
enum cases=10000;
import std.range;
bool isEven(int i){
	switch(i){
		static foreach(I;0..cases){
		//foreach(I;enumlist!(iota(cases))){
			case I: return isEvenImpl!I;
		}
		default: assert(0);
}}
template Val(int V){
	enum Val=V;
}
alias seq(T...)=T;
template enumlist(alias R){
	alias enumlist=seq!();
	static foreach(e;R){
		enumlist=seq!(enumlist,Val!e);
}}
unittest{
	import std;
	alias A=enumlist!(iota(5));
	A.stringof.writeln;
}
unittest{
	import std;
	7.isEven.writeln;
}
>

static foreach(I;0..cases){ //2.86s
foreach(I;enumlist!(iota(cases))){ //7.30s

Not going to do more tests but I believe you should stick with static each when possible but im pretty sure they share bigO details

August 26

On Tuesday, 26 August 2025 at 18:48:47 UTC, monkyyy wrote:

>

Since enum foreach is being deleted and nore properly implimented (ugh that not why I report bugs; to remove features)

No. 'enum foreach' never did anything different from normal foreach. The new error stops anyone from thinking it does mean something different. There's nothing to stop that feature being implemented if you can convince people it is worth the syntax sugar.

August 27

On Tuesday, 26 August 2025 at 18:48:47 UTC, monkyyy wrote:

>
#!opend -unittest -main -run app.d
bool isEvenImpl(int I)()=>! I%2;
enum cases=10000;
import std.range;
bool isEven(int i){
	switch(i){
		static foreach(I;0..cases){
		//foreach(I;enumlist!(iota(cases))){
			case I: return isEvenImpl!I;
		}
		default: assert(0);
}}
template Val(int V){
	enum Val=V;
}
alias seq(T...)=T;
template enumlist(alias R){
	alias enumlist=seq!();
	static foreach(e;R){
		enumlist=seq!(enumlist,Val!e);
}}
unittest{
	import std;
	alias A=enumlist!(iota(5));
	A.stringof.writeln;
}
unittest{
	import std;
	7.isEven.writeln;
}
>

static foreach(I;0..cases){ //2.86s
foreach(I;enumlist!(iota(cases))){ //7.30s

Apples to oranges here.

Enumlist is a giant template with ctfe.

Static foreach vs foreach on the same ct sequence should be equal performance.

Note that biggest differences are that ct foreach can do break and continue, and only is valid in a function. As you point out in this post you can also do static foreach on a range.

The ct acrobatics that were necessary for ct foreach before static foreach existed I don’t want to return to.

-Steve

August 27

On Wednesday, 27 August 2025 at 10:29:20 UTC, Steven Schveighoffer wrote:

>

Static foreach vs foreach on the same ct sequence should be equal performance.

All alias foreach's must be on an aliasSeq that must exist, thats a downside

Op didnt seem to be thinking about ct bigO so presumably my data point is the reliveant one here even if its only 300%; avoiding creating seq's is on the table.