0
$\begingroup$

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:

notebook snippet

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");

which produces enter image description here

$\endgroup$
0
$\begingroup$

I'll mention one somewhat hacky way; inserting a string into Message.

In my WSTP templates, I'll use a variable in myFunc::errormsg:

:Begin:
:Function:       my_C_func
:Pattern:        myFunc[x_Integer]
:Arguments:      { x }
:ArgumentTypes:  { Integer }
:ReturnType:     Manual
:End:
:Evaluate: 
    myFunc::errormsg = "`1`"

Then, in my C++ code, I'll invoke Message[myFunc::errormsg, err]:

void my_C_func(int x) {

    try { 
        library_func(x);
        WSPut...

    } catch(string err) {

        // must send 'err' back to Mathematica

        WSPutFunction(stdlink, "EvaluatePacket", 1);

        // Message[myFunc::errormsg, err]
        WSPutFunction(stdlink, "Message", 2);

            // myFunc::errormsg = MessageName[myFunc, "errormsg"]
            WSPutFunction(stdlink, "MessageName", 2);
            WSPutSymbol(stdlink, "myFunc");
            WSPutString(stdlink, "errormsg");

            WSPutString(stdlink, err.c_str());

        WSEndPacket(stdlink);
        WSNextPacket(stdlink);
        WSNewPacket(stdlink);

        WSPutSymbol(stdlink, "$Failed");
    }
}

Though yet untested, this should give me the desired behaviour. Though surely there is a better way!

| improve this answer | |
$\endgroup$
  • $\begingroup$ Oh joy, it works! $\endgroup$ – Anti Earth Mar 1 at 15:56
  • 1
    $\begingroup$ This is not a hacky way. Message is designed to be called with multiple arguments. Normally you don't have a fixed message string. You would have a message template with several slots, which are filled from the rest of Message's arguments. $\endgroup$ – Szabolcs Mar 1 at 16:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.