[interop] Unexpected cross-language object printing behavior
When objects from Python (and possibly other languages) are printed (either directly in the console or via console.log()), the other language's printing behavior is expected. However, Graal.js uses a custom format for printing foreign objects. The same is also true the other way around: JS objects are printed in Python without consulting toString(). This is unexpected behavior from the user's point of view. Maybe the new interop messages (e.g. toDisplayString()) can help to make this more consistent
Repro session
$ polyglot --jvm --shell
GraalVM MultiLanguage Shell 20.1.0
Copyright (c) 2013-2019, Oracle and/or its affiliates
JavaScript version 20.1.0
Python version 3.8.2
python> class A:
+ def __repr__(self):
+ return "Hello from Python"
+
python> A()
Hello from Python
python> print(A())
Hello from Python
python> str(A())
'Hello from Python'
python> js>
js> Polyglot.eval("python", "A()")
{} # `Hello from Python` expected
js> console.log(Polyglot.eval("python", "A()"))
{} # `Hello from Python` expected
js> class B { toString() { return "Hello from JS" } }
js> console.log(new B())
Hello from JS
js> python>
python> import polyglot
python> polyglot.eval(language="js", string="new B()")
<foreign '{}'> # `Hello from JS` expected
python> print(polyglot.eval(language="js", string="new B()"))
<foreign object at 0xeabecf5> # `Hello from JS` expected
/cc @timfel @eregon @LeonBein @teresalasarow
As a data point after discussion with @timfel @fniephaus and a few others this is what made sense for Ruby:
foreign.to_sreturns InteropLibrary#toDisplayString()foreign.inspecttries to format the foreign object as if it was Ruby, notably showing members and their value, without recursion (with extra info to show it's foreign, sinceinspectis "debugging output")
The current implementation in TruffleRuby is here.
toDisplayString(rubyObject) does rubyObject.inspect (if side effects allowed). Which isn't really consistent with the other direction, but far more useful in practice than calling to_s.
Python's to_s is str()and inspect is repr().
Not sure about JS, does it have only toString()?
One consideration I had (more relevant if a language only has one conversion to string) is if we can't find anything useful to show in inspect then calling toDisplayString might be good. Also played with just always appending toDisplayString() in inspect, but that gets kind of verbose/repetitive, e.g., for an array. "Array" is basically the only clear "interop type" right now, so maybe simply including toDisplayString() except for arrays (which likely don't have much extra info besides the array elements) might be a good compromise.
cc @woess
As a note, it's useful for polyglot programmers to both see the foreign's view of an object (to get the full information about the foreign object) and the current language's view of the object (e.g. to find which members are available, integrate better with local objects, etc).