How to print an object in NQP ? (For debugging purposes)
It is easy in Raku:
class Toto { has $.member = 42; }
class Titi { has $.member = 41; has $.toto = Toto.new }
my $ti = Titi.new;
say $ti;
# Titi.new(member => 41, toto => Toto.new(member => 42))
dd $ti;
# Titi $ti = Titi.new(member => 41, toto => Toto.new(member => 42))
- It seems more complicated in NQP
class Toto { has $!member; sub create() {$!member := 42}};
class Titi { has $!member; has $!toto; sub create() {$!member := 41; $!toto := Toto.new; $!toto.create; }}
my $ti := Titi.new;
say($ti);
Cannot stringify this object of type P6opaque (Titi)
Of course, no .gist method, the code calls nqp::encode which finally expects a string.
Reducing the problem to an MRE:
Simplifying the solution:
In summary, add a
Strmethod.This sounds simple but there's a whole lot of behind-the-scenes stuff to consider/explain.
nqp vs raku
The above solution is the same technique raku uses; when a value is expected by a routine/operation to be a string, but isn't, the language behavior is to attempt to coerce to a string. Specifically, see if there's a
Strmethod that can be called on the value, and if so, call it.In this case NQP's
NQPMu, which is way more barebones than raku'sMu, doesn't provide any defaultStrmethod. So a solution is to manually add one.More generally, NQP is a pretty hostile language unless you know raku fairly well and have gone thru A course on Rakudo and NQP internals.
And once you're up to speed on the material in that course, I recommend you consider the IRC channels #raku-dev and/or #moarvm as your first port of call rather than SO (unless your goal is specifically to increase SO coverage of nqp/moarvm).
Debugging the compiler code
As you will have seen, the NQP code you linked calls
.sayon a filehandle.That then calls this method.
That method's body is
$str ~ "\n". That code will attempt to coerce$strto a string (just as it would in raku). That's what'll be generating the "Cannot stringify" error.A search for "Cannot stringify" in the NQP repo only matched some Java code. And I bet you're not running Rakudo on the JVM. That means the error message must be coming from MoarVM.
The same search in the MoarVM repo yields this line in
coerce.cin MoarVM.Looking backwards in the routine containing that line we see this bit:
This shows the backend, written in C, looking for and invoking a "method" called
Str. (It's relying on an internal API (6model) that all three layers of the compiler (raku, nqp, and backends) adhere to.)Customizing the
StrmethodYou'll need to customize the
Strmethod as appropriate. For example, to print the class's name if it's a type object, and the value of its$!barattribute otherwise:Despite the method name, the nqp
sayroutine is not expecting a rakuStrbut rather an nqp native string (which ends up being a MoarVM native string on the MoarVM backend). Hence the need fornqp::coerce_is(which I found by browsing the nqp ops doc).self.HOW.name(self)is another example of the way nqp just doesn't have the niceties that raku has. You could write the same code in raku but the idiomatic way to write it in raku isself.^name.