ROOT::RWhy!

(15 June 2018)

Background

ROOT is implementing new interfaces following new interface styles. We follow C++ Core Guidelines where reasonable in our context. Most noticeably this means

  • use of references as parameters instead of pointers,
  • massive reduction of virtual functions (and calls), no more TObject inheritance,
  • use of stdlib classes (std::vector, std::string) instead of TList and friends,
  • new classes are in namespace ROOT; headers are in include/ROOT/ and are included as <ROOT/...>; libraries are starting with libROOT...
  • separation of concerns, including separation of internal (ROOT::Internal::) and user-facing functionality,

We do not do this because we love to exercise the newest C++ features. We do this because it makes code much easier to use, reducing interface size. We want to reduce the time you spend debugging memory errors (e.g. due to ROOT’s “PAW-style” ownership model) or type cast errors. We want to use types that you know (std library types) instead of our pre-stdlib versions. We want to cause compile-time failures where possible, instead of (hopefully) catching an error at runtime (think TFile::Open("foo.root", "RECRAETE"), double bins[] = {0., 1., 10., 50.}; new TH1F("h", "h", 4, bins)). We want to be thread-safe by default, not relying on global state (gPad used by hist->Draw() versus pad->Draw(hist)) We want to have the right default behavior - after 20 years of experience of what “right” means.

While we are at it we decided to also cover crucial existing classes, giving them an updated implementation. This has been nicknamed “ROOT 7”. We are currently working on a new graphics system that is HTML5 / CSS / JavaScript based, a new histograms library, and an update to the TTree facilities. You will be hearing news on all of these parts on the coming months - most notably at the ROOT Workshop in Sarajevo, September 10-13, 2018.

Why not to keep the same name.

We needed to name these new classes. Let’s take the TPad class: we want to keep new code using the new TPad very similar to code using the old TPad; reading the code should make it obvious what it does if you know ROOT6’s TPad. So we try to re-use the names - “pad” is a concept that ROOT user’s know, and we all call it “pad”. Let’s stick to “pad” then.

We started by introducing ROOT::Experimental::TPad next to TPad. (We keep things in ROOT::Experimental:: until we are fairly certain that the interface will be stable, at which point they move to ROOT::.) That worked - but only sort of:

Fully qualified name

Because the “old” TPad is in the global namespace, new code had to qualify it as ::TPad very often, and when referring to the new TPad, we had to type ROOT::Experimental::TPad even from inside the namespace ROOT::Experimental, because some uses of template might happen in a different lookup context. This made new code much more verbose, and fragile: an #include of a ROOT6 header might change the available type names, and might make a ROOT:: header mean something else. Bad, bad, bad.

Referring to types

When we were talking about types we had to say “ROOT 7 TPad” or “new TPad”. Often we shortened this to “TPad”. And we were often talking past each other - “o, you mean the old TPad”. We noticed that humans, just like compilers, were confused. Fairly terrible.

Tooling

ROOT uses file names that are derived from the classes they contain, e.g. TPad.cxx. Doxygen got totally confused by duplicate file names. Even though we always specified exactly which class and \file we’re talking about, a bug in doxygen made the reference guide go belly up; only one of (old|new) TFile.cxx was generated! This wasn’t just a problem with doxygen: other tools (e.g. IDEs) failed, too.

Expert Guidance

Luckily we have connections with smart people who make a living of cases like this, e.g. Nico Josuttis. They told us, without even thinking: do not reuse type names. Nico pointed out that we have a naming scheme that allows people detect what’s ROOT and what’s not; we should just slightly adjust that, so it’s clear what’s following old versus new style, to keep the recognition factor, and to clarify the correspondence between old and new types.

Conclusion

After months of experimenting with keeping the same names for new classes we decided this would not be sustainable. It barely worked for us; opening this to users would create massive confusion (“TPad isn’t compiling for me!”). We needed to change names.

Naming options

Pad

We could have used ROOT::Pad. Many of us were in favor of this style. We do expect that users will have using namespace ROOT in their files - I believe we’re realistic here :-) We will even have root [0] coming up with an implicit using namespace ROOT - after all, this is meant to be a cooperative interpreter! But File or Pad are really really generic names; including the wrong headers will #define this away! We would have to use longer type names to avoid that - which is counterproductive, and not a real guarantee that this is solved. It’s also not helping when talking: “the top-left pad”. Or was that mean to say “the top-left Pad”? Is this ROOT6 / the generic “pad” concept, or ROOT::Experimental::Pad?

ROOT::RPad

What about switching “T” to “R”? People would get confused at first, but we count on us, the community, to get used to this. It’s making clear that this is “not your regular T class”. Just because a class starts with R you now know:

  • it’s in #include <ROOT/RClassName.hxx>
  • it’s in the namespace ROOT::
  • you need to link a library libROOT... The leading T was part of the Taligent coding convention that ROOT employed when it was started (and that leaves its traces until today). Using R keeps the class recognizable a ROOT class.

ROOT::RTPad

One could simply prefix TPad with R, reminding us of ROOT. Several people favored this option; others thought that this is too close to ROOT::ROOTPad, i.e. a repetition of the namespace name.

Conclusion

After several weeks of discussions, plenty of good, technical arguments being collected for all options, we converged to ROOT::RPad as naming convention for new interfaces. As ROOT::RDataFrame is one of the first classes to be released that’s following the new interface style, it was released as, well, ROOT::RDataFrame. The ROOT::Experimental:: classes will follow this renaming.

TL;DR

Keeping old names for new implementations, but stuffing them into ROOT:: as a way to distinguish old and new, is a terrible idea. We have chosen ROOT::RWhatever as the naming convention for new classes that follow the new ROOT interface conventions. That was not an easy, obvious choice, but the result of a long convergence process, including experimenting with ROOT::TWhatever.