On Tue, 25 May 2021 at 13:31, Sergey B Kirpichev email@example.com wrote:
solve(x**2 == 1/2)
as you might notice, this is fully legal Python syntax. Unfortunately the semantics is such that sympy has no way to determine what is actually going on, this is why they invented all those helper functions shown above.
This is a SymPy special "solution". Nothing in Python prevents from returning a non-boolean from __eq__(): https://docs.python.org/3/reference/datamodel.html#object.__eq__
For example, instead you could use singletons. In fact, every object in symbolic math is a singleton. x**2 is such, (x + 1)**2 - 2*x - 1 - is another, different one. To test structural equality in this approach - you can use "is", instead of "==".
Although nothing in Python prevents defining __eq__() how you want and having it return other values can still be problematic to do so because of the way that __eq__() is tied to __hash__() and used in dicts and sets. Python the language made the decision that the == operator is also used for equality in dicts and sets. If x**2 == 1/2 were to return a symbolic equation object then it would imply that symbolic objects could not be used in Python's important container types.
The overloaded use of == in Python also leads to a tension between wanting e.g. 1 == 1.0 when == is used explicitly but perhaps not wanting 1 and 1.0 to be interchangeable in a dict/set:
On that basis I would say that unless you are sure you have no need to use objects as dict keys or in sets then you should define __eq__() so that a==b returns a bool. Also a==b should only return True in the cases where a and b are interchangeable and you genuinely don't care which of the two objects you would get.