root-project / root

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

[PyROOT] Error when copying a tuple into a specific position of a vector of tuples in PyROOT #8875

Open vepadulano opened 3 years ago

vepadulano commented 3 years ago

Describe the bug

Insertion of a tuple into a vector seems to be buggy on the Python side

>>> import ROOT
>>> a = ROOT.std.vector('tuple<long, long, double, double>')(2)
>>> b = ROOT.std.make_tuple[ROOT.long, ROOT.long, ROOT.double, ROOT.double](1, 2, 3, 4)
>>> a[0] = b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: tuple<long,long,double,double>& std::vector<tuple<long,long,double,double> >::operator[](unsigned long __n) =>
    TypeError: none of the 2 overloaded methods succeeded. Full details:
  ROOT::Internal::TEmulatedTuple<long,long,double,double>& tuple<long,long,double,double>::operator=(ROOT::Internal::TEmulatedTuple<long,long,double,double>&&) =>
    ValueError: could not convert argument 1 (object is not an rvalue)
  ROOT::Internal::TEmulatedTuple<long,long,double,double>& tuple<long,long,double,double>::operator=(const ROOT::Internal::TEmulatedTuple<long,long,double,double>&) =>
    TypeError: could not convert argument 1

While this works at the prompt

root [0] std::vector<std::tuple<long,long,double,double>> myvec{2};
root [1] std::tuple<long,long,double,double> myt{1,2,3,4};
root [2] myvec[0] = myt;

I couldn't understand how to reproduce the issue with TEmulatedTuple which is defined internally in TCling starting at https://github.com/root-project/root/blob/de302abeae86368724e69a7a0e7a24b2dff28f07/core/metacling/src/TCling.cxx#L3876

Expected behavior

Insertion of a tuple into a vector of tuples should work in PyROOT.

Setup

conda environment with ROOT 6.24/02 on Fedora32

Additional context

First reported on the forum at https://root-forum.cern.ch/t/using-std-tuple-in-pyroot/46347/3

etejedor commented 3 years ago

It seems that std::tuple is being replaced by ROOT::Internal::TEmulatedTuple. The same error can be reproduced with:

>>> b = ROOT.std.make_tuple[ROOT.int](1)
>>> c = ROOT.std.make_tuple[ROOT.int](1)
>>> b.__assign__(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: none of the 2 overloaded methods succeeded. Full details:
  ROOT::Internal::TEmulatedTuple<int>& tuple<int>::operator=(ROOT::Internal::TEmulatedTuple<int>&&) =>
    ValueError: could not convert argument 1 (object is not an rvalue)
  ROOT::Internal::TEmulatedTuple<int>& tuple<int>::operator=(const ROOT::Internal::TEmulatedTuple<int>&) =>
    TypeError: could not convert argument 1
dpiparo commented 6 months ago

This looks like a nasty mix of runtime reflection information and IO (we use TEmulatedTuple to abstract from implementation details of the tuple class in the stl to perform IO in a simple way). @pcanal would you be able to suggest a path to improve the current situation?

dpiparo commented 3 months ago

The problem seems to be on the PyROOT side. If you do this:

c = a[1]
c = b

everything works. Can it be linked to the fact that operator[] returns a reference?