Hello,
during the migration to a new PyROOT release in ROOT 6.22.00 I’ve found the case that looks like a regression to me.
Operators () and [] defined in C++ base classes are not propagated by PyROOT when other operators are defined in derived classes.
In new PyROOT definition of new operators prevents operators from base class to be considered at all.
In legacy PyROOT definition of new operators prevents only similar operators from base class to be considered at all, i.e. operator() in derived class would prevent operators() from base class to be considered for overload resolution.
The using Base::operator[]/()
declaration has no effect on PyROOT behavior.
Here comes minimal reproducer (2.8 KB) for the problem where there is a base class with operator[]
and operator()
and 2 derived classes, with and without additional operators in derived class.
I’ve also put observed behaviors for PyROOTs I’ve tried as comments before each invokation of operators:
#!/usr/bin/python3
import ROOT
import cppyy
code = '''
struct Base {
Base() {};
const std::string& operator[](const std::string& x) {
return x;
};
const std::string& operator()(const std::string& x) {
return x;
};
int operator()(int x) {
return x;
};
};
struct Problematic: public Base {
Problematic(): Base{} {};
using Base::operator[];
double operator()(double x) {
return x+1;
};
};
struct Good: public Base {
Good(): Base{} {};
};
'''
def main():
ROOT.gInterpreter.Declare(code)
problem = cppyy.gbl.Problematic()
good = cppyy.gbl.Good()
try:
# ROOT 6.22/00 -- modern PyROOT -- will fail
# ROOT 6.22/00 -- legacy PyROOT -- will fail
# ROOT 6.20/04 -- legacy PyROOT -- will fail
print("Trying to call Problematic::operator()(const std::string&):")
_ = problem('Call succeeded')
print(_, '\n')
except TypeError:
print("Call to Problematic::operator()(const std::string&) failed\n")
try:
# ROOT 6.22/02 -- modern PyROOT -- will fail
# ROOT 6.22/00 -- modern PyROOT -- will fail
# ROOT 6.22/00 -- legacy PyROOT -- will succeed
# ROOT 6.20/04 -- legacy PyROOT -- will succeed
print("Trying to call Problematic::operator[](const std::string&):")
_ = problem['Call succeeded']
print(_, '\n')
except TypeError:
print("Call to Problematic::operator[](const std::string&) failed\n")
try:
# ROOT 6.22/02 -- modern PyROOT -- will select double overload
# ROOT 6.22/00 -- modern PyROOT -- will select double overload
# ROOT 6.22/00 -- legacy PyROOT -- will select double overload
# ROOT 6.20/04 -- legacy PyROOT -- will select double overload
print("Trying to call Problematic::operator()(int):")
inp = int(1)
_ = problem(inp)
if inp != _:
print("Called Problematic::operator()(double)\n")
else:
print("Call succeeded")
except TypeError:
print("Call to Problematic::operator()(int) failed\n")
try:
# ROOT 6.22/02 -- modern PyROOT -- will succeed
# ROOT 6.22/00 -- modern PyROOT -- will succeed
# ROOT 6.22/00 -- legacy PyROOT -- will succeed
# ROOT 6.20/04 -- legacy PyROOT -- will succeed
print("Trying to call Good::operator[](const std::string&):")
_ = good['Call succeeded']
print(_, '\n')
except TypeError:
print("Call to Good::operator[](const std::string&) failed\n")
try:
# ROOT 6.22/02 -- modern PyROOT -- will succeed
# ROOT 6.22/00 -- modern PyROOT -- will succeed
# ROOT 6.22/00 -- legacy PyROOT -- will succeed
# ROOT 6.20/04 -- legacy PyROOT -- will succeed
print("Trying to call Good::operator[](const std::string&):")
_ = good['Call succeeded']
print(_, '\n')
except TypeError:
print("Call to Good::operator[](const std::string&) failed\n")
if __name__ == "__main__":
main()
The observed behavior that any operator definition in derived class blocks all operators from base class in new PyROOT looks very strange to me.
Please, can anyone help me to understand whether this behavior is expected from PyROOT or it is a regression?
Best wishes,
Konstantin
ROOT Version:
- ROOT 6.22.02 with modern PyROOT
- ROOT 6.22.00 with modern PyROOT
- ROOT 6.22.00 with legacy PyROOT
- ROOT 6.20.04 with legacy PyROOT
Platform: Ubuntu 18.04 LTS
Compiler:
- g++-9
Python version: 3.6.9
_CMake flags for ROOT: -D CMAKE_CXX_COMPILER="g++-9" -D CMAKE_C_COMPILER="gcc-9" -D CMAKE_CXX_STANDARD=17 -D python_version=3 -D minuit2=ON -D builtin_xrootd=ON