Access to method from base class

Hi, I have a C++ class MyInterpolator that inherits from ROOT::Math::Interpolator.

One of the things I do is overload the Eval and Deriv methods to accept the signature “Double_t Eval(Double_t * x, Double_t *) const” so that I can feed the MyInterpolator into a TF1 constructor. The base class method has the signature Eval(double x).

In a CINT terminal, I can do the following:

*  ROOT v5.34/18  *
root [0] .L t2x.C+
root [1] t2x::MyInterpolator * inter = t2x::t2xer(12,0)
root [2] inter->Eval(0.2)
(const double)5.03465017533624382e-01
root [3] Double_t x[] = {0.2}
root [4] inter->Eval(x,0)
(const Double_t)5.03465017533624382e-01
root [5] inter->Eval( // Tab-complete to show signatures

Double_t Eval(Double_t* x, Double_t*) const

So it looks like CINT automatically knows about base class methods when they are called, but it doesn’t show them when you tab-complete.

In PyROOT, when I try to do the same thing, I get this:

In [1]: import ROOT,array
In [2]: ROOT.gROOT.ProcessLine(".L t2x.C+")
Out[2]: 0L
In [3]: inter = ROOT.t2x.t2xer(12,0)
In [4]: x = array.array('d',[0.2])
In [5]: inter.Eval(x,ROOT.nullptr)
Out[5]: 0.5034650175336244
In [6]: inter.Eval(0.2)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-c25abf27dfa4> in <module>()
----> 1 inter.Eval(0.2)

TypeError: Double_t MyInterpolator::Eval(Double_t* x, Double_t*) =>
    takes at least 2 arguments (1 given)
In [7]: help(inter.Eval)
Eval(self, Double_t* x, Double_t*) method of __main__.t2x::MyInterpolator instance
    Double_t MyInterpolator::Eval(Double_t* x, Double_t*)

I know I can manually overload/hide the Eval(double x) method in my derived class and just make it call the base class method with the same signature, but I am wondering if there is some automated way to make PyROOT aware of base class methods? In my case, I only need one or two methods for the class, but I could imagine that for a big class (say a derived version of TH1) doing it for all the methods would be very tedious.

Jean-François

Jean-François,

sorry, I’m not really following. If the derived class method has a different signature than the base class one, C++ rules says that the base class method is hidden for overload selection.

Trying a simple example, and indeed CINT seems to be in the wrong here. This is fixed (sorry for that word choice; I understand that this is not what you want) in ROOT6 w/ Cling. (You can still file a JIRA ticket for it; it would be a question of backwards compatibility.)

The normal way of getting base class methods into the derived class is with ‘using’, but that does not work with the dictionaries (those methods are not exposed).

For automatic use on Python, the only thing I can think of is to rewrite a method to call the derived, and if failed (i.e. catch the exception), try the base class overloads.

Cheers,
Wim

My derived class MyInterpolator already had “using ROOT::Math::Interpolator::Eval;” in the declaration, which is why it works in CINT after .L t2x.C+.

I guess your comment on the dictionaries is the right explanation for why it doesn’t work in PyROOT.

Since my classes are rather small, I just added an explicit Eval(Double_t) overload in the derived class. All it does is call the base class method, so it shouldn’t change anything on the C++ and CINT side.

Jean-François

Jean-François,

[quote=“jfcaron”]My derived class MyInterpolator already had “using ROOT::Math::Interpolator::Eval;” in the declaration, which is why it works in CINT after .L t2x.C+.[/quote]good, then it’ll be fine in ROOT6 (CINT really does not require a using).

[quote=“jfcaron”]I guess your comment on the dictionaries is the right explanation for why it doesn’t work in PyROOT.[/quote]Yes; we decided at the time that it was too much trouble to try to fix it. The only places where ‘using’ appears are in RooFit (AFAIK), and those few are handled explicitly in Pythonize.cxx.

Cheers,
Wim