PyObject __repr__, __str__ and toString
Jeff Allen <[email protected]>
| Newsgroups | gmane.comp.lang.jython.devel |
|---|---|
| Message-ID | <[email protected]> |
We're discussing this in a couple of places already, but I wanted to ask
here in case there are old hands subscribed who can shed any light.
http://bugs.jython.org/issue2719
https://github.com/jythontools/jython/pull/126
PyObject.java contains some comments I've never understood and have had
difficulty following
(https://hg.python.org/jython/file/tip/src/org/python/core/PyObject.java#l218).
It seems advice only relevant to those who extend PyObject, which is
mostly us. And we certainly don't follow it in PyObjectDerived which
contains the mechanism by which Python authors override __str__ and
where toString delegates to __repr__.
Generally, the plain dunder methods in Jython correspond to tp_* slots
in CPython, and methods with a name like int___add__ to which they
delegate are the implementation functions. Overriding __add__ to call
int___add__ is equivalent to the action in CPython of placing a function
pointer in a tp-slot. At present, __str__ and __repr__ do not follow
this convention: __str__ defaults to __repr__ by this mechanism, as
expected. However, we tell people not to override these methods, but to
define the result of either by overriding Object.toString. No real clue
there what to do if they should give different results. Moreover, we
expose (the non-final) Java PyObject.__repr__ as Python object.__str__,
and something we call object_toString as object.__repr__. The logic of
this cross-wiring is not explained, except that there will be a stack
overflow if you don't. But why is this the right way to solve that problem?
To me the obvious pattern is something like:
1. __str__ calls final object___str__, which is exposed as object.__str__ .
2. object___str__ calls __repr__
3. __repr__ calls final object___repr__, which is exposed as
object.__repr__ .
4. toString calls __str__ and we discourage overriding it because
that's what __str__ is for in Python objects.
Then in PyObjectDerived we do not override toString, but as normal all
slot functions do their look-up for exposed versions and toString
continues to call __str__. I think this defuses the stack overflow in a
natural way, but if it doesn't, we look for some other solution than the
one we have now.
I notice that in CPython, these slots are wrapped with a little more
logic (e.g.
https://github.com/python/cpython/blob/2.7/Objects/object.c#L453),
whereas in Jython we tend to call __str__ and so on directly. This may
also be part of the right solution for us: to be investigated.
Jeff
--
Jeff Allen