-
Notifications
You must be signed in to change notification settings - Fork 77
Fix non-const Color::operator[] to return mutable reference #701
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
base: main
Are you sure you want to change the base?
Fix non-const Color::operator[] to return mutable reference #701
Conversation
Applied non optimal Changes to operator[] for having the desired behaviour. Added respective unit tests Signed-off-by: Nuno Guedelha <nunoguedelha@gmail.com>
Refactored Color::operator[] implementation (const version too) using a common private function, made possible by the use of const_cast<> for returning a non constant float&. Signed-off-by: Nuno Guedelha <nunoguedelha@gmail.com>
- renamed GetMutableRGBAfromIndex - Fixed line length > 80 Signed-off-by: Nuno Guedelha <nunoguedelha@gmail.com>
Regarding
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution! The changes look good to me. Do you mind adding a line in the Migration guide to indicate that float& Color::operator[](const unsigned int _index)
now returns a reference?
Sure @azeey . On it.. |
@azeey , since this change breaks API it would go into a major version, so 10x right? In such case I need to add a section Gazebo Math 10.X above Gazebo Math 8.X to 9.X... please let me know. |
Yes, please add a new section. Thanks! |
Signed-off-by: Nuno Guedelha <nunoguedelha@gmail.com>
@azeey , done! |
@azeey , side note regarding the Ruby and Python bindings... Currently, it seems to me that:
I know that Pybind11 supports functions returning references, but since it is not implemented for I would say this deserves a separate PR. What do you think @azeey ? |
You can skip the Ruby tests/bindings. We are more focused on Python these days. But I was under the impression that mutation of the individual colors was implemented via gz-math/src/python_pybind11/src/Color.cc Lines 118 to 129 in 77f7c04
For gz-math/src/python_pybind11/src/Color.cc Lines 150 to 151 in 77f7c04
And provide the non-const version to |
Considering the behaviour I've observed, the bindings you mentioned above are for the read-only accessors, right? Indeed the following test example: clr.set(0.1, 0.2, 0.3, 0.4)
self.assertAlmostEqual(0.1, clr.r())
self.assertAlmostEqual(0.2, clr.g())
self.assertAlmostEqual(0.3, clr.b())
self.assertAlmostEqual(0.4, clr.a())
print("clr.r() =", clr.r(), "clr.g() =", clr.g(), "clr.b() =", clr.b(), "clr.a() =", clr.a()) ...will pass and output: clr.r() = 0.10000000149011612 clr.g() = 0.20000000298023224 clr.b() = 0.30000001192092896 clr.a() = 0.4000000059604645 But then, mutation won't work: clr.r() = 0.5 ...will fail and output: 136: clr.r() = 0.5
136: ^^^^^^^
136: SyntaxError: cannot assign to function call here. Maybe you meant '==' instead of '='?
Failed
Actually, I think this is already the non-const version, since the const version should have been defined with the .def("__getitem__",
py::overload_cast<const unsigned int>(&Class::operator[], py::const_)); Using the original non-const version to mutate the component will also fail: 136: Traceback (most recent call last):
136: File "/Users/nunoguedelha/dev/gz-math/src/python_pybind11/test/Color_TEST.py", line 188, in test_color
136: clr[0] = 0.6
136: ~~~^^^
136: TypeError: 'gz.math.Color' object does not support item assignment ...probably because we need to define a binding through I'm looking deeper into |
🦟 Bug fix
Fixes #575
Summary
This fixes the issue by having the
operator[]
function (non const version) returning a reference to theColor
component, of typefloat&
, instead of just the component value, of typefloat
. This PR takes in account all the discussion thread in PR #579 which was previously closed.The fix consists in two main steps:
operator[]
function implementation for avoiding code duplication.Desired Behaviour
operator[]
function to return a reference to a float. Since functions can not be overloaded if they differ only in the return type, we get the desired behaviour by changing the prototype of the existing function. Although the impact is minor, this breaks API so the change is branched off themain
branch._index
input (refer to @azeey comment in Color [] changed to call by reference #579 (comment)_):NAN_F
, then0.9
.Unit Tests
operator[]
andclr.SetFromHSV
, so the last check onclr.SetFromHSV(300, 0.5, 1.0)
is done usingR()
,G()
,B()
,A()
accessors, etc.Refactoring
We can't have the common behaviour of both mutable and const versions of
operator[]
implemented:operator[]() const
and somehow called byoperator[]()
since the first returns a value, not a reference;operator[]()
and called byoperator[]() const
since the first would then have to be declaredconst
.The easiest solution is to:
const float&
;const_cast<float&>
to cast the returned const reference to a non-const.How to Reproduce
If we try the following snippet in the namespace
gz
:The result is changed by the fix…
Before Fix
The snippet won’t compile and instead return the error: “expression is not assignable”, as the left expression is an rvalue.
After Fix
The snippet will compile and the Color object component
_r
will be changed.In addition:
will output NAN_F twice (even after overwriting
clr[4]
).Checklist
codecheck
passed (See contributing)Note to maintainers: Remember to use Squash-Merge and edit the commit message to match the pull request summary while retaining
Signed-off-by
andGenerated-by
messages.