Method overloading with Rust traits #2530
-
Hello, I have a Rust struct that I have exposed to Python using pyo3. I would like to implement overloaded methods using the typical Rust traits-based scheme, to allow a common named method to accept multiple types, e.g. add(f64), add(f32) but more complex than this. My problem is that pyo3 doesn't seem to allow traits on pymethods. I get the error:
Is there no way to get around this to implement overloaded methods, or am I missing something? Thanks for your help. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 5 replies
-
Can you share a minimal snippet of the code that you intuitively wrote which hit the error? I'd be happy to comment on the technical limitations, what you can do instead, and how we might be able to improve PyO3 in this area. |
Beta Was this translation helpful? Give feedback.
-
Thank you so much for your time. I have a struct called Raster, which, as the name implies, is effectively a large raster data structure like a 2D array. I'd like to be able to perform various ops on them, like add, subtract, multiply, etc. two Rasters together, or a Raster and a single f64, etc. Here's an example that actually caused the above stated error when used:
Then, of course, I'd ideally like to be able to use this to, within Python, say something like: new_raster = raster1 + raster2 or new_raster = raster1 + 50.0 I'm not sure if that helps you or not, but essentially, I would ideally like to use Rust's trait system to overload operators. In reading some other things on this forum, I get the sense that the complexity of doing so may not make it possible for pyo3 to have this feature. If that's the case, then I completely understand, but I just wanted to make sure that I wasn't missing something obvious. |
Beta Was this translation helpful? Give feedback.
-
Right, I see. This idea of using In principle we could support it (with limitations such as if you imported the trait under a different name like The recommended way you can achieve this at the moment is to just define your Python #[derive(FromPyObject)]
enum RasterOrF64 {
Raster(Raster),
F64(f64)
}
#[pymethods]
impl Raster {
fn __add__(&self, other: RasterOrF64) -> Self {
match other {
RasterOrF64::Raster(r) => self.clone() + r,
RasterOrF64::F64(f) => self.clone() + f,
}
}
} |
Beta Was this translation helpful? Give feedback.
Right, I see. This idea of using
#[pymethods]
onstd::ops::Add
is interesting.In principle we could support it (with limitations such as if you imported the trait under a different name like
OpsAdd
the macro would not recognise it). However, given theAdd
trait is generic (essentially overloadable), this would create a technical challenge which would likely make the PyO3 framework quite complicated. IMO for now there are higher priority items to tackle first.The recommended way you can achieve this at the moment is to just define your Python
__add__
as normal. You can make it handle multiple types using anenum
input: