Bug 12313 – Unneeded stack temporaries created by tuple foreach
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D1 (retired)
Platform
All
OS
All
Creation time
2014-03-07T07:23:00Z
Last change time
2014-04-30T04:13:11Z
Keywords
industry
Assigned to
nobody
Creator
public
Comments
Comment #0 by public — 2014-03-07T07:23:09Z
This issue is present for both D1 and D2 but seems to be partially compensated by better optimizer in dmd2.
Current foreach implementation (ForeachStatement::semantic) creates a local stack temporary for every element of expression tuple foreach it iterates over:
=== test.d ===
struct A
{
int a, b, c;
}
void main()
{
A a;
// this empty loop creates variables as copies of every member of a
foreach (var; a.tupleof)
{}
}
======
There are two issues with it:
1) stack space can easily go out of control with algorithms on long tuples (it has just his us in Sociomantic)
2) it prevents one from writing to `var` and forces to use ugly index idiom instead: `foreach (index, var; a.tupleof) { a.tupleof[index] = 42; }`
Can't tell possible impact of removing those temporaries right now, needs some experiments.
Comment #1 by dlang-bugzilla — 2014-03-07T07:24:14Z
Have you tried using "ref"? IIRC that worked for my code.
Comment #2 by public — 2014-03-07T07:48:35Z
Does not work for D1: "Error: no storage class for value var"
It does not also make any sense from language semantics point of view as a.tupleof is effectively tuple of variable aliases. And there is no such thing as `ref alias`.
Sounds more like a hack to fix another hack.
Comment #3 by dlang-bugzilla — 2014-03-07T07:54:23Z
(In reply to comment #2)
> It does not also make any sense from language semantics point of view as
> a.tupleof is effectively tuple of variable aliases. And there is no such thing
> as `ref alias`.
>
> Sounds more like a hack to fix another hack.
I see it more like the foreach body being like a function (whose body is implicitly inlined). In this context, "ref" works out fine. Since .tupleof only enumerates fields, and not functions, each member can be mapped to a concrete value (and thus can work with "ref").
Comment #4 by public — 2014-03-07T07:56:56Z
foreach != tuple foreach
latter is more like template declaration that gets instantiated for every tuple element as an argument
Comment #5 by k.hara.pg — 2014-03-07T22:48:17Z
(In reply to comment #4)
> foreach != tuple foreach
>
> latter is more like template declaration that gets instantiated for every tuple
> element as an argument
If you want to iterate the elements of the container (array, range, tuple, etc) without copying, use 'ref'.
Comment #6 by public — 2014-03-08T03:45:10Z
D1 does not have ref foreach.
tuple is not a container.
Comment #7 by dlang-bugzilla — 2014-03-08T03:58:48Z
Since D2 has a trivial workaround, can we agree that this is a D1-only bug?
Comment #8 by public — 2014-03-08T03:59:53Z
I'd say it is D1 bug and D2 enhancement request ;)
But for practical concerns it can be considered D1-only, no problem.
Comment #9 by github-bugzilla — 2014-04-29T20:06:41Z