I've written a Mathematica package (see here) which uses WSTP to call a C/C++ library. Some possible user-errors are known by the package and can be detected and reported by the front-end package code. However, some user-errors are reported by the C library and must be sent on to Mathematica; these error messages are not known a-priori, and the errors cannot be detected by my package itself.
This seems incompatible with the standard way to report package errors, using Message
. For example, if the package function myFunc
accepts positive integers, the canonical way to handle this is:
myFunc::badarg = "First argument must be a positive integer"
myFunc[x_Integer] :=
If[ x<0,
(Message[myFunc::badarg]; $Failed),
...
]
(* of course there are more elegant ways to handle this usign patterns *)
The result looks like this in Mathematica:
In this example, we see the message in myFunc::badarg
is fixed, and set a-priori.
In theory, even my WSTP functions can be given messages of this kind;
:Begin:
:Function: my_C_func
:Pattern: myFunc[x_Integer]
:Arguments: { x }
:ArgumentTypes: { Integer }
:ReturnType: Manual
:End:
:Evaluate:
myFunc::badarg = "First argument must be a positive integer"
Still, these error messages are fixed.
But now consider when my_C_func
involves an error detected by the internal C library:
void my_C_func(int x) {
try {
library_func(x);
WSPut...
} catch(string err) {
// must send 'err' back to Mathematica
WSPut...
}
}
I would like to 'channel' err
to the front-end, to report it like I would the myFunc::badarg
error message. Unfortunately, Message[]
accepts symbol::tag
which is a-priori set, and we don't know what message err
contains.
Is that at all possible? Otherwise, how can I fake the look of Message
?
Currently, my hacky solution is to completely forego using Message
, instead using Echo
.
// must send 'err' back to Mathematica
WSPutFunction(stdlink, "EvaluatePacket", 1);
WSPutFunction(stdlink, "Echo", 2);
WSPutString(stdlink, err);
WSPutString(stdlink, "Error ");
WSEndPacket(stdlink);
WSNextPacket(stdlink);
WSNewPacket(stdlink);
WSPutSymbol(stdlink, "$Failed");