How to unify named and anonymous scripts?

Hello,

I would like to unify “named” and “anonymous” scripts in a single file.

Named Script

Feeding Sources Files To ROOT: C++ Scripts mentions named script, for instance:

void named()
{
    int a=0;
}

named.C (30 Bytes)
This type may be relevant for testing purpose because:

  • it accepts arguments
  • variables scope is well-defined:

In a named script, the objects created on the stack are deleted when the function exits.

Example:

$ root named.C
   ------------------------------------------------------------------
  | Welcome to ROOT 6.30/06                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Apr 04 2024, 12:44:07                 |
  | From tags/v6.30.06@v6.30.06                                      |
  | With c++ (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0                   |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------

root [0]
Processing named.C...
root [1] a
input_line_11:2:3: error: use of undeclared identifier 'a'
 (a)
  ^
Error in <HandleInterpreterException>: Error evaluating expression (a)
Execution of your code was aborted.

Anonymous Script

Let’s also consider “anonymous script”, e.g.:

{
    int a=0;
}

anonymous.C (17 Bytes)
What is the official name?

Since the scope is global, they may be useful for:

  • inspecting created objects
  • drawing figures

Example:

$ root anonymous.C
   ------------------------------------------------------------------
  | Welcome to ROOT 6.30/06                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Apr 04 2024, 12:44:07                 |
  | From tags/v6.30.06@v6.30.06                                      |
  | With c++ (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0                   |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------

root [0]
Processing anonymous.C...
root [1] a
(int) 0

How to unify them?

I naively tried to merge these 2 types:

#if defined(FUNCTION_INTERFACE)
void merged()
#endif
{
    int a=0;
}

merged.C (70 Bytes)

But when the macro is not defined, I get an error:

$ root -q merged.C
   ------------------------------------------------------------------
  | Welcome to ROOT 6.30/06                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Apr 04 2024, 12:44:07                 |
  | From tags/v6.30.06@v6.30.06                                      |
  | With c++ (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0                   |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------


Processing merged.C...
In file included from input_line_8:1:
/.../merged.C:4:1: error: expected unqualified-id
{
^

Asking for help

How would you combine those 2 types?

Setup

ROOT v6.30/06
Built for linuxx8664gcc on Apr 04 2024, 12:44:07
From tags/v6.30.06@v6.30.06
With c++ (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0

Compiled from source

Additional context

Calling named script

One solution might be to call a named script from an anonymous script, .e.g.:
library.C:

void modify(size_t& num_points) {
    num_points = 3;
}

void library() {}

main.C:

{
    size_t num_points {0};
    modify(num_points);
}

Test:

root {library,main}.C
------------------------------------------------------------------
| Welcome to ROOT 6.24/06                        https://root.cern |
| (c) 1995-2021, The ROOT Team; conception: R. Brun, F. Rademakers |
| Built for linuxx8664gcc on Sep 02 2021, 14:20:23                 |
| From tags/v6-24-06@v6-24-06                                      |
| With                                                             |
| Try '.help', '.demo', '.license', '.credits', '.quit'/'.q'       |
------------------------------------------------------------------

root [0]
Processing .../library.C...
Processing .../main.C...
root [2] num_points
(unsigned long) 3

But it is tedious.

Environment variables

An alternative would be to use environment variables, e.g. uranie/dataserver/show_parallel.C · v6-30_uranie · Uranie CEA / ROOT / roottest · GitLab

{
    string figure = gSystem->Getenv("FIGURE");
    string input_file = gSystem->Getenv("INPUT_FILE");
    string configuration_file = gSystem->Getenv("CONFIGURATION_FILE");
    
    [...]
}

However, I must pay attention to side effects.

Hi,

Is perhaps giving a name to the unnamed macro an option? It could be a relatively easy way forward.

Cheers,
Danilo

Could this variant be maybe helpful for your use case?

merged.C:

{
    int a = 123;

    a = a+5;
}

void merged()
{
    cout << a << endl;
}

(The unnamed scope braces are actually unnecessary, you can just leave them out)

1 Like

Thank your for your answer. However I have difficulty to understand your suggestion.

Do you propose to change:

{
    int a=0;
}

to:

void named()
{
    int a=0;
}

?
If that is the case, how can I access a?

If your file name.C is:

int a;
void named() {
   a = 1;
}

Then you can access a after the macro execution:

root [0] .x named.C
root [1] a
(int) 1
root [2] 

Sorry if I missed a point …

1 Like

Thank you for you variant.

I removed the unnamed scope braces:

int a = 123;
a = a+5;

void merged()
{
    cout << a << endl;
}
$ sha256sum merged.C 
fc9682f47672e59f6cbd717054697a2210f6327f480f5c25d3437197bafa3abc  merged.C
$ root merged.C 
   ------------------------------------------------------------------
  | Welcome to ROOT 6.30/06                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Apr 04 2024, 12:44:07                 |
  | From tags/v6.30.06@v6.30.06                                      |
  | With c++ (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0                   |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------

root [0] 
Processing merged.C...
In file included from input_line_8:1:
/.../merged.C:2:1: error: C++ requires a type specifier for all declarations
a = a+5;
^

Does it mean these braces are necessary?

To make the variable “a” visible after the macro execution you should put its declaration outside the braces. But the executable code should be put inside braces (that’s C++). The file named.C should be:

int a = 123;

void named()
{
    cout << a << endl;
    a = a+5;

}

The when you execute it you get what is expected:

root [1] .x named.C
123
root [2] a
(int) 128
root [3] 
1 Like

No, it works for me with and without braces, but maybe you need to use newer ROOT 6.32 instead of your version.

int a = 123;
a = a+5;

void merged()
{
    cout << a << endl;
}


 root -l merged.C 
root [0] 
Processing merged.C...
128

Also:


{
int a = 123;
a = a+5;
}

void merged2()
{
    cout << a << endl;
}

root [0] 
Processing merged2.C...
(int) 128
root [1] .q

1 Like

Yes true.
but you cannot put any executable code outside the braces. For instance this does not work:

int a = 0;
for (int i=0; i<10; i++) { a = a+10;}

void merged()
{
    cout << a << endl;
}
2 Likes

Now I understand. Thank your for your explanations.

Using argument is also natural:
merged.C:

int a;

void merged(int value=1)
{
    a = value;
    cout << "a: " << a << endl;
}

Default argument:

$ root -l -q merged.C

Processing merged.C...
a: 1
$ root -l merged.C
root [0] 
Processing merged.C...
a: 1
root [1] a
(int) 1

User argument:

$ root -l -q "merged.C(-1)"

Processing merged.C(-1)...
a: -1
$ root -l "merged.C(-1)"
root [0] 
Processing merged.C(-1)...
a: -1
root [1] a
(int) -1

OK. Thank you for your correction.

I confirm it works with ROOT 6.32:
merged.C:

int a = 123;
a = a+5;

void merged()
{
    cout << a << endl;
}
$ docker run -v ${PWD}:/userhome --user $(id -u) rootproject/root:6.30.06-ubuntu22.04 root /userhome/merged.C
   ------------------------------------------------------------------
  | Welcome to ROOT 6.30/06                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Apr 03 2024, 10:42:17                 |
  | From tags/v6.30.06-0-g4f4e716372@v6.30.06-0-g4f4e716372          |
  | With c++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0                   |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------


Processing /userhome/merged.C...
In file included from input_line_8:1:
/userhome/merged.C:2:1: error: C++ requires a type specifier for all declarations
a = a+5;
^
$ docker run -v ${PWD}:/userhome --user $(id -u) rootproject/root:6.32.02-ubuntu24.04 root /userhome/merged.C
   ------------------------------------------------------------------
  | Welcome to ROOT 6.32.02                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Jun 18 2024, 04:46:14                 |
  | From tags/v6-32-02@v6-32-02                                      |
  | With c++ (Ubuntu 13.2.0-23ubuntu4) 13.2.0                        |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------


Processing /userhome/merged.C...
128

Thank you for this solution.

However, merged() function doesn’t seem to be called.

Here is a slight modification of your example:
merged.C:

{
    int a = 123;
}

void merged()
{
    cout << "a:" << a << endl;
}
$ docker run -v ${PWD}:/userhome --user $(id -u) rootproject/root:6.32.02-ubuntu24.04 root /userhome/merged.C
   ------------------------------------------------------------------
  | Welcome to ROOT 6.32.02                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Jun 18 2024, 04:46:14                 |
  | From tags/v6-32-02@v6-32-02                                      |
  | With c++ (Ubuntu 13.2.0-23ubuntu4) 13.2.0                        |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------


Processing /userhome/merged.C...
(int) 123

Tell me if I misunderstood something.

Thank you for your example.

I confirm I get an error:

$ docker run -v ${PWD}:/userhome --user $(id -u) rootproject/root:6.32.02-ubuntu24.04 root /userhome/merged.C
   ------------------------------------------------------------------
  | Welcome to ROOT 6.32.02                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Jun 18 2024, 04:46:14                 |
  | From tags/v6-32-02@v6-32-02                                      |
  | With c++ (Ubuntu 13.2.0-23ubuntu4) 13.2.0                        |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------


Processing /userhome/merged.C...

 *** Break *** segmentation violation
 Generating stack trace...
 0x00007f38d8b2c062 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d8b298df in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d8b2a905 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d8b2eb69 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d8b2f335 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d8b2a0da in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d8b2a905 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d8a75e9f in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d8b64ad2 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d8b65bf2 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d803c7a9 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d803d980 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d7fa391a in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d80a4181 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d80a4344 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d80b41b4 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d80b6069 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d809cc70 in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d7e9388c in <unknown> from /opt/root/lib/libCling.so
 0x00007f38d7eac0cf in TCling::ProcessLine(char const*, TInterpreter::EErrorCode*) + 0x128f from /opt/root/lib/libCling.so
 0x00007f38d7eac734 in TCling::ProcessLineSynch(char const*, TInterpreter::EErrorCode*) + 0x124 from /opt/root/lib/libCling.so
 0x00007f38de880497 in TApplication::ExecuteFile(char const*, int*, bool) at TApplication.cxx:? from /opt/root/bin/../lib/libCore.so
 0x00007f38debb3980 in TRint::ProcessLineNr(char const*, char const*, int*) + 0x60 from /opt/root/bin/../lib/libRint.so
 0x00007f38debb568d in TRint::Run(bool) + 0x29d from /opt/root/bin/../lib/libRint.so
 0x000055719e106303 in main + 0x53 from /opt/root/bin/root.exe
 0x00007f38de2371ca in <unknown> from /lib/x86_64-linux-gnu/libc.so.6
 0x00007f38de23728b in __libc_start_main + 0x8b from /lib/x86_64-linux-gnu/libc.so.6
 0x000055719e106355 in _start + 0x25 from /opt/root/bin/root.exe

You have then two options:

Either:

int a = 123;
a = a+5;

void merged()
{
    cout << "a" << a << endl;
}

root [0] 
Processing /tmp/merged.C...
a128

or using unnamed scope as ‘main function’ and then calling merged from it.

{
int a = 123;
a = a+5;
merged();
}

void merged()
{
    cout << "a" << a << endl;
}

root [0] 
Processing /tmp/merged.C...
a128

Thank you for your reply.

I would choose your first solution.
Because with the second one, I may not be able to give an argument from command line.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.