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 ofTList
and friends, - new classes are in
namespace ROOT
; headers are ininclude/ROOT/
and are included as<ROOT/...>
; libraries are starting withlibROOT...
- 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 leadingT
was part of the Taligent coding convention that ROOT employed when it was started (and that leaves its traces until today). UsingR
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
.