[BUG]: enum should not be silently converted to float in method call
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 18k
- Forks
- 2.3k
- Avg merge
- 5d 17h
- Merged PRs (30d)
- 10
Description
Required prerequisites
- Make sure you've read the documentation. Your issue may be addressed there.
- Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
- Consider asking first in the Gitter chat room or in a Discussion.
What version (or hash if on master) of pybind11 are you using?
v2.11.1
Problem description
Enums (including enum class) will be implicitly converted to ints or floats during method calls. This behavior is surprising and can lead to problems where the wrong function is selected during overload resolution.
There should be a way to disable implicit conversion of enums to other types.
Consider the following case:
PYBIND11_MODULE(cmake_example, m) {
py::enum_<Color>(m, "Color")
.value("RED", Color::RED)
.value("GREEN", Color::GREEN)
.value("BLUE", Color::BLUE);
m.def("f", [](double, double) { return "f(double, double)"; });
m.def("f", [](double, Color) { return "f(double, Color)"; });
}
Calling f(0, Color.RED) from python incorrectly calls the f(double, double) overload. If the Color enum were not implicitly convertible, this would not occur.
Backwards Compatibility Concerns
I understand that there may be concerns about backwards compatibility. If these concerns are significant enough, then there should at least be a way to opt out of implicit conversion for enums
Reproducible example code
Full example code (C++):
#include <pybind11/pybind11.h>
namespace py = pybind11;
enum class Color { RED = 0, GREEN = 1, BLUE = 2 };
int add_int(int i, int j) { return i + j; }
double add_float(double x, double y) { return x + y; }
PYBIND11_MODULE(cmake_example, m) {
m.def("add_int", &add_int);
m.def("add_float", &add_float);
py::enum_<Color>(m, "Color")
.value("RED", Color::RED)
.value("GREEN", Color::GREEN)
.value("BLUE", Color::BLUE);
/// Example of overload failure - calling f(0, Color) in python
/// returns "f(double, double)" due to implicit conversion
m.def("f", [](double, double) { return "f(double, double)"; });
m.def("f", [](double, Color) { return "f(double, Color)"; });
}
Full example code (Python):
import cmake_example as m
# Probable bug - m.Color should _not_ be implicitly convertible to int
# Both of these should throw an invalid argument exception
print(m.add_int(1, m.Color.BLUE)) # Calls add_int, prints 3
print(m.add_float(0.5, m.Color.BLUE)) # Calls add_float, prints 2.5
# Overload case
print(m.f(0.0, m.Color.BLUE)) # Calls f(double, Color) (CORRECT)
print(m.f(0, m.Color.BLUE)) # Calls f(double, double) (INCORRECT)
Output of python:
3
2.5
f(double, Color)
f(double, double)
Is this a regression? Put the last known working version here if it is.
Not a regression
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the reported PYBIND11_MODULE example and reproduce the calls to add_int, add_float, and the overloaded f entry point. Trace enum argument conversion and overload selection, then verify that enum-to-integer or enum-to-float conversion is rejected or can be opted out of without breaking the demonstrated overload behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, python
- Domain
- api, backend-api-design
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100