Differences between C++ and Python

Many of the Nevis summer students have some previous experience with Python, but not with C++. Here’s a quick overview of the differences to get you started. Pay attention to the prompts; they tell you whether the example is in ROOT/C++ or Python.

  • C++ statements end with a semi-colon. Python statements end with a RETURN; no semi-colons.

    In [] myhist.FillRandom("gaus",10000)
    In [] myhist.Fit("gaus")
    
    [] myhist.FillRandom("gaus",10000); myhist.Fit("gaus");
    
  • Python control structures are defined by indentations. The indentation is mandatory; ending (or increasing) the indentation is the same as ending (or nesting) the structure. This means that when you start working with pyroot scripts, you must be careful with the TAB and SPACE keys. Note the colon at the end of the for statement; colons are also needed at the end of if statements:

    for jentry in xrange( entries ):
        # get the next tree in the chain and verify
        ientry = mychain.LoadTree( jentry )
        # More stuff
    print ("The loop is over")
    

    C++ control structures (e.g., if statements, loops) are indicated by curly braces ({}).1 Any indentation is for the convenience of humans; the compiler doesn’t need it:

    for (Int_t jentry=0; jentry<nentries; jentry++) {
        Int_t ientry = LoadTree(jentry);
        // More stuff
    }
    std::cout << "The loop is over" << std::endl;
    
  • C++ uses pointers, and ROOT makes liberal use of them in the code it generates for you (in .C files, etc.). Python does not use pointers, which means you don’t have to remember whether to use “.” or “->”:

    In [] hist = ROOT.TH1D("example","my second histogram",100,-3,3)
    In [] hist.FillRandom("gaus")
    
    [] TH1* hist = new TH1D("example","my second histogram",100,-3,3);
    [] hist->FillRandom("gaus");
    
  • You have might picked up on this from the examples above: C++ has strict rules about types, and expects you to specify them when you create a new variable.2 Python determines types dynamically, and you rarely have to specify them:

    In [] x = 2*3
    In [] yae = ROOT.TH1D("test4","yet another example",200,-100,100)
    
    [] Double_t x = 2 * 3;
    [] TH1D yae = TH1D("test4","yet another example",200,-100,100);
    
  • The ROOT C++ interpreter, cling, knows the names of all the ROOT classes. You can type the following directly into interactive ROOT without anything that resembles Python’s import statement:

    [] TH1D* example4 = new TH1D("example4","my fourth histogram",100,-3,3);
    [] example4->Draw();
    

    However, if you write a stand-alone program in C++, you have need a #include for the header of any class that’s not part of the standard C++ specification:3

    #include <TH1D.h>
    TH1D* example4 = new TH1D("example4","my fourth histogram",100,-3,3);
    example4->FillRandom("gaus",10000);
    

1

I’m simplifying here. All the code in this course you’ve have seen so far use curly braces. I don’t want to confuse you any further (except for this footnote).

2

Since I hate to lie to you, I should mention the C++ auto keyword, which lets C++ determine the type for you. Both of the following are correct:

TH1D* hist = new TH1D("hist","title",100,-3,3);

auto hist = new TH1D("hist","title",100,-3,3);

This can be a great timesaver if a C++ function returns something with a type like std::vector<std::pair<int,double>>::const_iterator. However, you have to be comfortable with C++ before using it, which is why I’m relegating this C++ tip to a footnote.

How comfortable with C++ do you have to be before you can use auto? Enough so that you understand why both of the above lines are not the best choice. A better choice would be:

auto hist = std::make_shared<TH1D>("hist","title",100,-3,3);

Now you know why it takes a lifetime to learn C++!

3

This is crucial if you decide to work on Exercise 11.