Skip to content

[Python][RDF] Enable Support for C++ Free Functions in RDF Define #19437

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

siliataider
Copy link
Contributor

@siliataider siliataider commented Jul 22, 2025

This Pull request:

This PR extends the RDataFrame pythonizations by adding support for passing C++ free functions to .Define() operations, with support for:

  • Templated functions
  • Overloaded functions
  • Functions taking any input/output combination of
    • Fundamental types
    • ROOT types (e.g. TObject-derived classes)
    • User-defined C++ classes

Quick demo:

import ROOT

ROOT.gInterpreter.Declare(""" 
struct MyStruct {
    int a;
    MyStruct() : a(0) {}
    MyStruct(int a_) : a(a_) {}
};
                          
float struct_a(const MyStruct& s) {
    return s.a;
}                          

bool is_even(int x) {
    return x % 2 == 0;
}
                          
bool is_even(int x, float y) {
    return x % 2 == 0 && x == y;
}                                                 

template <typename T>
bool is_even_t(const T x, const float y) {
    return x % 2 == 0 && x == y;
}
""")

rdf = ROOT.RDataFrame(3) \
         .Define("x", "(int)rdfentry_") \
         .Define("y", "(float)rdfentry_") \
         .Define("is_even_x", ROOT.is_even, ["x"]) \
         .Define("is_even_x_y", ROOT.is_even, ["x", "y"]) \
         .Define("is_even_t", ROOT.is_even_t[int], ["x", "y"]) \
         .Define("my_struct", "MyStruct((int)rdfentry_)") \
         .Define("struct_a", ROOT.struct_a, ["my_struct"]) 
         
rdf.Display().Print()

Output:

+-----+-----------+-----------+-------------+-----------------+----------+---+----------+
| Row | is_even_t | is_even_x | is_even_x_y | my_struct       | struct_a | x | y        | 
+-----+-----------+-----------+-------------+-----------------+----------+---+----------+
| 0   | true      | true      | true        | @0x55d3fead9190 | 0.000000 | 0 | 0.000000 | 
+-----+-----------+-----------+-------------+-----------------+----------+---+----------+
| 1   | false     | false     | false       | @0x55d3fead9190 | 1.000000 | 1 | 1.000000 | 
+-----+-----------+-----------+-------------+-----------------+----------+---+----------+
| 2   | true      | true      | true        | @0x55d3fead9190 | 2.000000 | 2 | 2.000000 | 
+-----+-----------+-----------+-------------+-----------------+----------+---+----------+

The implementation works by converting the free function to std::function using the function's signature.

Warning

This currently doesn't work if the function takes templated types as input arguments like STL containers (e.g. std::vector<T>) because of #19358
Concretely, this doesn't work:

bool has_even_sum(const RVec<int>& v) {
   return Sum(v) % 2 == 0;
} 

Important

Prerequisites / TODO:

Checklist:

  • tested changes locally
  • updated the docs (if necessary)

Copy link

github-actions bot commented Jul 22, 2025

Test Results

    21 files      21 suites   3d 5h 34m 42s ⏱️
 3 215 tests  3 215 ✅ 0 💤 0 ❌
65 798 runs  65 798 ✅ 0 💤 0 ❌

Results for commit 4df654d.

♻️ This comment has been updated with latest results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

cppyy.gbl.std.function(...) fails for template types like std::vector<int>, ROOT::RVec<int>
1 participant