root-project / root

The official repository for ROOT: analyzing, storing and visualizing big data, scientifically
https://root.cern
Other
2.71k stars 1.29k forks source link

Problem using type with default template parameters in the interpreter #15996

Open Nowakus opened 4 months ago

Nowakus commented 4 months ago

Check duplicate issues.

Description

The new cppyy produces an error when we try to call GetBranchAttr on one of our DataVector branches.

Reproducer

Reproducer using only the ATLAS environment, no files necessary:

export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase 
source $ATLAS_LOCAL_ROOT_BASE/user/atlasLocalSetup.sh
asetup main--dev4LCG,latest,Athena
python
    import ROOT, cppyy.ll
    ROOT.TClass.GetClass('DataVector<xAOD::PixelCluster_v1>').HasDictionary()
True
    cppyy.ll.cast['DataVector<xAOD::PixelCluster_v1>'](0)
TypeError: Could not find "cppyy_cast<DataVector<xAOD::PixelCluster_v1>>" (set cppyy.set_debug() for C++ errors):
  Failed to instantiate "cppyy_cast<DataVector<xAOD::PixelCluster_v1>>(int)"

but using a typedef to the DataVector works (note the real type of the returned object):

    cppyy.ll.cast['xAOD::PixelClusterContainer_v1>'](0)
<cppyy.gbl.DataVector<xAOD::PixelCluster_v1> object at 0x11cbd2c0>

and after the previous call autoloaded some libraries, the real type starts to work as well:

    cppyy.ll.cast['DataVector<xAOD::PixelCluster_v1>'](0)
<cppyy.gbl.DataVector<xAOD::PixelCluster_v1> object at 0x1f542770>

ROOT version

6.32+, possibly since 6.30

Installation method

SFT dev nightlies

Operating system

alma9

Additional context

No response

amete commented 1 week ago

Hi @guitargeek, has there been any progress on this? Many thanks.

guitargeek commented 1 week ago

As discussed offline, the underlying reason seems to be that the forward declaration of DataVector is inconsistent with the definition.

Here is the forward declaration:

template <class T, class BASE> class DataVector;

And here is the definition:

template <class T, class BASE = typename DataVectorBase<T>::Base>
class DataVector : public BASE
{

The definition has a default template argument, while the forward declaration has not. Depending on what is hit in the lookup, the instantiation with just one template parameter might therefore fail.

So, I think the issue needs to be fixed on the ATLAS Athena side, also adding the default value for the BASE template parameter to the forward declaration.

Let me know if this fixes it, so the issue can be closed!

scott-snyder commented 1 week ago

That's not actually a forward declaration of DataVector; it's a forward declaration of ROOT::Meta::Selection::DataVector. That class does not default its second argument.

The actual forward declaration that we're getting complaints about here seems to be synthesized by cling. In one case we see an error message pointing at the rootmap file:

Forward declarations from /cvmfs/atlas-nightlies.cern.ch/repo/sw/main_Athena_x86_64-el9-gcc13-opt/2024-11-12T2101/Athena/25.0.22/InstallArea/x86_64-el9-gcc13-opt/lib/Athena.rootmap:4:44: note: template is declared here
template <typename T, typename BASE> class DataVector;

In any case, adding a default to the selection class forward declaration changes neither what's written to the rootmap file nor the error.

guitargeek commented 1 week ago

I see. Thanks for the follow up!

Then I guess this needs to be followed up be the experts for the rootmap files. I'll change the issue description to highlight that this is not a Python issue, since the exact same thing happens in the C++ ROOT interpreter.

Reproducer:

export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase 
source $ATLAS_LOCAL_ROOT_BASE/user/atlasLocalSetup.sh
asetup main--dev3LCG,latest,Athena
root
   ------------------------------------------------------------------
  | Welcome to ROOT 6.35.01                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Nov 16 2024, 00:04:28                 |
  | From heads/master@v6-35-01-139-g2aa2426cbf                       |
  | With g++ (GCC) 14.2.0                                            |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------

Using the real type initially doesn't work:

root [0] DataVector<xAOD::PixelCluster_v1>{0}
ROOT_prompt_0:1:1: error: too few template arguments for class template 'DataVector'
DataVector<xAOD::PixelCluster_v1>{0}
^
Forward declarations from /cvmfs/atlas-nightlies.cern.ch/repo/sw/main--dev3LCG_Athena_x86_64-el9-gcc14-opt/2024-11-10T1100/Athena/25.0.22/InstallArea/x86_64-el9-gcc14-opt/lib/Athena.rootmap:5:44: note: template is declared here
template <typename T, typename BASE> class DataVector;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~       ^

But the typedef works:

root [1] xAOD::PixelClusterContainer_v1{0}
(xAOD::PixelClusterContainer_v1) { nullptr }

After using the typedef, the real type works too:

root [2] DataVector<xAOD::PixelCluster_v1>{0}
(DataVector<xAOD::PixelCluster_v1>) { nullptr }

The problem seems to be related to the fact that the the DataVector class has a second template parameter with a default.

Nowakus commented 3 days ago

Some more findings that make this problem even more strange: 1) Loading the class with GetClass() works fine and the problem does not show up afterwards:

root [0] TClass::GetClass("DataVector<xAOD::PixelCluster_v1>")    
  (TClass *) 0x4833740    
root [1] DataVector<xAOD::PixelCluster_v1>{0}     
  (DataVector<xAOD::PixelCluster_v1>) { nullptr }

2) After trying once, and getting the error, the second attempt goes through:

root [0] DataVector<xAOD::PixelCluster_v1>{0}
ROOT_prompt_0:1:1: error: too few template arguments for class template 'DataVector'

root [1] DataVector<xAOD::PixelCluster_v1>{0}
  (DataVector<xAOD::PixelCluster_v1>) { nullptr }