Content-Length: 495757 | pFad | https://github.com/RustPython/RustPython/pull/424

E6 Add object.{__lt__, __le__, __gt__, __gt__} by janczer · Pull Request #424 · RustPython/RustPython · GitHub
Skip to content

Add object.{__lt__, __le__, __gt__, __gt__} #424

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

Merged
merged 4 commits into from
Feb 12, 2019

Conversation

janczer
Copy link
Contributor

@janczer janczer commented Feb 9, 2019

No description provided.


Err(vm.new_type_error(format!(
"'>' not supported between instances of {} and {}",
i.borrow(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using the Display trait, go for vm.py_str to properly call the __str__ or __repr__ of the object.

@windelbouwman
Copy link
Contributor

Is this code required? If the __lt__ attribute is not present, < will not work anyway right?

@janczer
Copy link
Contributor Author

janczer commented Feb 10, 2019

Yes, < will not work but, if I run RustPython I get different error from the python:

RustPython:

>>>>> a = object()
>>>>> a < 1
Traceback (most recent call last):
  File <stdin>, line 0, in <module>
TypeError: Unsupported method: __lt__

Python3.7.2:

>>> a = object()
>>> a < 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'object' and 'int'

Looks like error from RustPython not so clear. @windelbouwman what do you think?

@windelbouwman
Copy link
Contributor

I am unsure what is the proper location to implement this. We might also choose to update the existing error message in Rustpython. We already raise the correct exception type, so the message should be expanded, right? I would look in the vm.rs file for the existing error and add proper type name information like in cpython.

@janczer
Copy link
Contributor Author

janczer commented Feb 10, 2019

We already raise the correct exception type, so the message should be expanded, right?

Yes.

I would look in the vm.rs file for the existing error and add proper type name information like in cpython.

The unsupported method error thorws on 251 line in vm.rs. Can you please tell me how I can expand the error?

@windelbouwman
Copy link
Contributor

The proper error message appears already to be implemented here: https://github.com/RustPython/RustPython/blob/master/vm/src/vm.rs#L554

The correct function to take a look at is call_or_unsupported. This function will first try the normal method (__add__), then the reverse method (__radd__ for example).

Take a look at the _lt method (https://github.com/RustPython/RustPython/blob/master/vm/src/vm.rs#L604). Maybe we could call here call_or_unsupported as well?

@janczer
Copy link
Contributor Author

janczer commented Feb 11, 2019

Looks like some work done in #433. Maybe I can add erros the same way?

@OddCoincidence
Copy link
Contributor

Looks like some work done in #433. Maybe I can add erros the same way?

Yep! The objobject comparison methods should return NotImplemented:

class MyClass:
    pass

assert MyClass().__le__(MyClass()) == NotImplemented
assert MyClass().__lt__(MyClass()) == NotImplemented
assert MyClass().__ge__(MyClass()) == NotImplemented
assert MyClass().__gt__(MyClass()) == NotImplemented

And VirtualMachine::{_le, _lt, _ge, _gt} should use call_or_unsupported. This page documents the appropriate fallbacks to use.

@janczer janczer force-pushed the add_object_lt_le_gt_ge branch from bfb122e to 0887b55 Compare February 12, 2019 14:32
@janczer
Copy link
Contributor Author

janczer commented Feb 12, 2019

@OddCoincidence I added the methods to object but when I run tests/snippets/builtin_max.py got error:

thread 'main' panicked at 'Inner error getting inner boolean', vm/src/obj/objbool.rs:60:9

What I'm doing wrong? Can you help me please

@cthulahoops
Copy link
Collaborator

cthulahoops commented Feb 12, 2019

Sounds like the same type of bug I fixed in: #441

builtin_max should use vm._gt rather than calling __gt__ itself.

@janczer
Copy link
Contributor Author

janczer commented Feb 12, 2019

@cthulahoops You are right! Thank you! Should we change all calling __gt__ to vm._gt and another simular methods?

@windelbouwman
Copy link
Contributor

Thats probably better. The magic methods should be used sparingly, preferably in wrapper methods.

vm/src/vm.rs Outdated
pub fn _lt(&mut self, a: &PyObjectRef, b: PyObjectRef) -> PyResult {
self.call_method(a, "__lt__", vec![b])
pub fn _lt(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__lt__", "__lt__", |vm, a, b| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reverse methods for these shouldn't be the same, i.e. they're not commutative like __eq__ and __ne__; a > b != b > a. Instead, as described here:

lt() and gt() are each other’s reflection, le() and ge() are each other’s reflection

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -100,7 +100,7 @@ fn float_lt(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
.ctx
.new_bool(v1 < objint::get_value(i2).to_f64().unwrap()))
} else {
Err(vm.new_type_error(format!("Cannot compare {} and {}", i.borrow(), i2.borrow())))
Ok(vm.ctx.not_implemented())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think float_{gt,ge,le} need this change as well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Thanks

pub fn _lt(&mut self, a: &PyObjectRef, b: PyObjectRef) -> PyResult {
self.call_method(a, "__lt__", vec![b])
pub fn _lt(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
self.call_or_unsupported(a, b, "__lt__", "__gt__", |vm, a, b| {
Copy link
Contributor

@windelbouwman windelbouwman Feb 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The opposite of < is >=, right? I would expect __lt__ to fail over to __ge__.

Copy link
Contributor

@OddCoincidence OddCoincidence Feb 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because call_or_unsupported flips the operands. If you think about it, a > b and b < a are equivalent. a > b and b <= a are not.

Also from the python docs:

lt() and gt() are each other’s reflection, le() and ge() are each other’s reflection

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yes, you are right! Sorry for that!

@windelbouwman windelbouwman merged commit e5af4ca into RustPython:master Feb 12, 2019
@janczer janczer deleted the add_object_lt_le_gt_ge branch February 12, 2019 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: https://github.com/RustPython/RustPython/pull/424

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy