Skip to content

Commit

Permalink
py/objboundmeth: Implement equality comparisons
Browse files Browse the repository at this point in the history
Currently different bound method instances will compare as unequal even
when both instances bind the same method and object. This is different
to the CPython implementation and, for example, will cause problems
when working with lists that contain callbacks since things like
list.remove() will not work correctly.

Fix this the obvious way by introducing a binary op and implementing
MP_BINARY_OP_EQUAL. A simple test case is provided.

Currently this is unconditionally compiled and on a Thumb2 system
(ports/nrf) it resulted in a 68 byte increase in code size.

Signed-off-by: Daniel Thompson <daniel@redfelineninja.org.uk>
  • Loading branch information
daniel-thompson committed Nov 14, 2020
1 parent b442d82 commit d198d29
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
23 changes: 23 additions & 0 deletions py/objboundmeth.c
Expand Up @@ -95,13 +95,36 @@ STATIC void bound_meth_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
}
#endif

STATIC mp_obj_t bound_meth_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
// We only implement equality tests
if (op != MP_BINARY_OP_EQUAL) {
return MP_OBJ_NULL; // op not supported
}

// Check types. It is tricky to sub-class a bound method so we can keep this very simple)
const mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in);
const mp_obj_type_t *rhs_type = mp_obj_get_type(rhs_in);
if (lhs_type->make_new || lhs_type->binary_op != bound_meth_binary_op || lhs_type != rhs_type) {
return MP_OBJ_NULL;
}

mp_obj_bound_meth_t *lhs = MP_OBJ_TO_PTR(lhs_in);
mp_obj_bound_meth_t *rhs = MP_OBJ_TO_PTR(rhs_in);
if (mp_obj_equal(lhs->meth, rhs->meth)) {
return mp_obj_new_bool(mp_obj_equal(lhs->self, rhs->self));
}

return mp_const_false;
}

STATIC const mp_obj_type_t mp_type_bound_meth = {
{ &mp_type_type },
.name = MP_QSTR_bound_method,
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
.print = bound_meth_print,
#endif
.call = bound_meth_call,
.binary_op = bound_meth_binary_op,
#if MICROPY_PY_FUNCTION_ATTRS
.attr = bound_meth_attr,
#endif
Expand Down
8 changes: 8 additions & 0 deletions tests/basics/boundmeth1.py
Expand Up @@ -28,3 +28,11 @@ def h(self, a, b, c, d, e, f):
A().f.x = 1
except AttributeError:
print('AttributeError')

# equality tests
i = A() # need methods to be bound from the same instance
m = i.f
print(m == i.f)
print(m != i.f)
print(m == i.g)
print(m != i.g)

0 comments on commit d198d29

Please sign in to comment.