Unexpected behavior of nested for loops when loading a macro with .L

Hi, I noticed what seems to be an unexpected behavior in Cling (ROOT 6.34.08, GCC 15.2.0, Linux). The following simple code works correctly when entered directly at the interactive prompt:

for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
cout << i << " " << j << endl;
}
}

However, if I put exactly the same code in a file (not inside a void function) and load it with .L test_loop.C I get:

0 0
0 1
0 2
0 3
0 4
0 5
0 6
0 7
0 8
0 9

The inner loop is executed only during the first iteration of the outer loop. Moreover, i and j remain visible in the interpreter:

root [1] i
(int) 10
root [2] j
(int) 10

If I put the same code inside a function and call the function the output is correct.
The same test with ROOT 6.28/08 produces a parsing error (expected unqualified-id) when the parser reaches the first for loop.

Thanks,
Alessandro

It could be a problem with your system or your ROOT. I don’t see the issue with the Ubuntu 24.04 binary of ROOT 6.34.08 (GCC 13.3), on Linux Mint. The ‘official’ download page (Release 63408 - ROOT) does not list any binary compiled with gcc 15.2.0 (the closest would be the MAC OS 15.4 version). You didn’t mention your OS or which ROOT binary (or compiled?), but if you are using a binary, it should be a version compiled with your same GCC version; otherwise, you should compile it yourself.

You try to use a so-called ROOT’s unnamed macro. Your source code must be enclosed in curly braces (I somehow remember that the “{” needed to be the very first line in a ROOT’s unnamed macro file):

{
 // ... your source code ...
}

BTW. To load and execute a macro, you should use “.x”, not “.L”.

With the curly braces it works. I thought it was illegal to use a for loop outside of any function (and why do the loop variables survive?). Perhaps the problem is with my own ROOT package: there is no package for Slackware Linux, so I built it myself.

Next time I’ll try the official packages first.

Thanks

couet@host-128-141-12-39 roottest % cat test_loop.C
void test_loop() {
   for (int i = 0; i < 10; ++i) {
      for (int j = 0; j < 10; ++j) {
         cout << i << " " << j << endl;
      }
   }
}%                                                                                                                                                                     couet@host-128-141-12-39 roottest % root           
   ------------------------------------------------------------------
  | Welcome to ROOT 6.41.01                        https://root.cern |
  | (c) 1995-2025, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for macosxarm64 on Jun 25 2026, 14:10:57                   |
  | From heads/master@v6-39-99-744-gc60cc226368                      |
  | With Apple clang version 21.0.0 (clang-2100.1.1.101) std201703   |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------

root [0] .x test_loop.C
0 0
0 1
0 2
0 3
0 4
0 5
0 6
0 7
0 8
0 9
1 0
1 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
2 0
2 1
2 2
2 3
2 4
2 5
2 6
2 7
2 8
2 9
3 0
3 1
3 2
3 3
3 4
3 5
3 6
3 7
3 8
3 9
4 0
4 1
4 2
4 3
4 4
4 5
4 6
4 7
4 8
4 9
5 0
5 1
5 2
5 3
5 4
5 5
5 6
5 7
5 8
5 9
6 0
6 1
6 2
6 3
6 4
6 5
6 6
6 7
6 8
6 9
7 0
7 1
7 2
7 3
7 4
7 5
7 6
7 7
7 8
7 9
8 0
8 1
8 2
8 3
8 4
8 5
8 6
8 7
8 8
8 9
9 0
9 1
9 2
9 3
9 4
9 5
9 6
9 7
9 8
9 9
root [1] .q
couet@host-128-141-12-39 roottest % root test_loop.C
root [0] 
Processing test_loop.C...
0 0
0 1
0 2
0 3
0 4
0 5
0 6
0 7
0 8
0 9
1 0
1 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
2 0
2 1
2 2
2 3
2 4
2 5
2 6
2 7
2 8
2 9
3 0
3 1
3 2
3 3
3 4
3 5
3 6
3 7
3 8
3 9
4 0
4 1
4 2
4 3
4 4
4 5
4 6
4 7
4 8
4 9
5 0
5 1
5 2
5 3
5 4
5 5
5 6
5 7
5 8
5 9
6 0
6 1
6 2
6 3
6 4
6 5
6 6
6 7
6 8
6 9
7 0
7 1
7 2
7 3
7 4
7 5
7 6
7 7
7 8
7 9
8 0
8 1
8 2
8 3
8 4
8 5
8 6
8 7
8 8
8 9
9 0
9 1
9 2
9 3
9 4
9 5
9 6
9 7
9 8
9 9
root [1] .q
couet@host-128-141-12-39 roottest % 

@couet The question/problem was about an unnamed macro. Note this in the original post:

Perhaps the title is a bit misleading. My point is that code which is not valid C++ (i.e. a for loop outside any function) does not produce an error in my current ROOT build when I load the file with the .L command. With just one loop, the code works (the loop variable survives in any case). The code breaks when I add a nested loop.

I guess couet is right: there is probably something wrong with my current ROOT build.

Your “current ROOT build” is fine.

You said earlier that with curly brackets it is working. That’ s right, you were missing them in your first example. I then sent you two ways to execute a ROOT macro. First with .x macro.Cat the ROOT prompt then by putting directly the macro name after the root command. That’s simple and it should work with your ROOT build. I put a name in the macro file but it works the same way without. The only problem you had was the missing curly brackets.

Poking around with ROOT, I have the feeling that sometimes a loop in an unnamed macro fails. It’s a nasty behaviour because, on my machine, I get it only if the macro is “complex” enough. For example, I took the official tutorial rf101_basics.C and added three vertical lines on the second pad:
rf101_basics.C (2.6 KB)

There are two macros: one is named and empty, the other one is unnamed and contains the original code plus my three lines at the very end.
On my machine (ROOT 6.34.08, GCC 15.2.0, Slackware Linux, self-built package), I get one vertical line on the plot at x = -4. If I look carefully, there are actually three lines attached to the canvas with the same x = -4, even though I explicitly set them at different coordinates.

root [1] c->GetListOfPrimitives()->ls()
OBJ: TList      TList   Doubly linked list : 0
TPad fXlowNDC=0.01 fYlowNDC=0.01 fWNDC=0.48 fHNDC=0.98 Name= rf101_basics_1 Title= rf101_basics_1 Option=
OBJ: TList    TList   Doubly linked list : 0
TFrame  X1= -10.000000 Y1=0.000000 X2=10.000000 Y2=0.083778
OBJ: TH1D    frame_x_10990070        Gaussian pdf. : 0 at: 0x109377a0
OBJ: RooCurve        gauss_Norm
   Projection of gaussian PDF : 0 at: 0x102ed9c0
OBJ: RooCurve        gauss_Norm
   Projection of gaussian PDF : 0 at: 0x10907940
OBJ: TH1D    frame_x_10990070        Gaussian pdf. : 0 at: 0x109377a0
OBJ: TPaveText       title   X1= -5.284489 Y1=0.086887 X2=3.951156 Y2=0.093727
TPad fXlowNDC=0.51 fYlowNDC=0.01 fWNDC=0.48 fHNDC=0.98 Name= rf101_basics_2 Title= rf101_basics_2 Option=
OBJ: TList    TList   Doubly linked list : 0
TFrame  X1= -10.000000 Y1=0.000000 X2=10.000000 Y2=321.832719
OBJ: TH1D    frame_x_1097ffd0        Gaussian pdf with data : 0 at: 0x10908970
OBJ: RooHist h_gaussData     Histogram of gaussData_plot__x : 0 at: 0x10906e60
OBJ: RooCurve        gauss_Norm
   Projection of gaussian PDF : 0 at: 0x1096c330
OBJ: TH1D    frame_x_1097ffd0        Gaussian pdf with data : 0 at: 0x10908970
TLine  X1=-4.000000 Y1=0.000000 X2=-4.000000 Y2=100.000000
TLine  X1=-4.000000 Y1=0.000000 X2=-4.000000 Y2=100.000000
TLine  X1=-4.000000 Y1=0.000000 X2=-4.000000 Y2=100.000000
OBJ: TPaveText       title   X1= -8.173656 Y1=333.778300 X2=6.840323 Y2=360.050359

Of course, the loop works fine in the named macro (as do the plain Draw() calls in the unnamed one). I also attach a minimal macro with the same loop (canvas, TF1, three TLines) which works correctly on my pc - so I think the loop alone is not the problem:
test_loop.C (411 Bytes)

Alessandro

Mixing “named” and “unnamed” ROOT macros in a C++ file is not allowed.
In a C++ file, you can have multiple “named” ROOT macros, or only a single “unnamed” one.

I didn’t know that, thank you. I’ve removed the void function, but nothing changes: the three lines are still at x = -4.
rf101_basics.C (2.6 KB)

One more thing: the loop enclosed in a lambda function works fine in the unnamed macro.

And that was the solution, moving the “{” to the very beginning of the file. I had completely forgotten that part. Thank you.