Calling Subsidiary Wolfram System Processes

Connecting to a subsidiary program via WSTP.

This starts a subsidiary Wolfram System process on the computer system used here:

link=LinkLaunch["math -mathlink"]

Here is a packet representing the first input prompt from the subsidiary Wolfram System process:

LinkRead[link]

This writes a packet representing text to enter in the subsidiary process:

LinkWrite[link,EnterTextPacket["10!"]]

Here is a packet representing the output prompt from the subsidiary process:

LinkRead[link]

And here is the actual result from the computation:

LinkRead[link]

The basic way that the various different objects involved in a Wolfram System session are kept organized is by using Wolfram Symbolic Transfer Protocol (WSTP) packets. A WSTP packet is simply an expression with a definite head that indicates its role or meaning.

Basic packets used in Wolfram System sessions.

The fact that (RefLink[LinkRead, paclet:ref/LinkRead]) returns an (RefLink[InputNamePacket, paclet:ref/InputNamePacket]) indicates that the subsidiary Wolfram System is now ready for new input:

LinkRead[link]

This enters two (RefLink[Print, paclet:ref/Print]) commands as input:

LinkWrite[link,EnterTextPacket["Print[a]; Print[b];"]]

Here is the text from the first (RefLink[Print, paclet:ref/Print]):

LinkRead[link]

And here is the text from the second (RefLink[Print, paclet:ref/Print]):

LinkRead[link]

No output line is generated, so the new packet is an (RefLink[InputNamePacket, paclet:ref/InputNamePacket]):

LinkRead[link]

Some additional packets generated in Wolfram System sessions.

If you enter input to the Wolfram Language using (RefLink[EnterTextPacket, paclet:ref/EnterTextPacket])["input"], then the Wolfram Language will automatically generate a string version of your output and will respond with (RefLink[ReturnTextPacket, paclet:ref/ReturnTextPacket])["output"]. But if you instead enter input using (RefLink[EnterExpressionPacket, paclet:ref/EnterExpressionPacket])[expr], then the Wolfram Language will respond with (RefLink[ReturnExpressionPacket, paclet:ref/ReturnExpressionPacket])[expr] and will not turn your output into a string.

Packets for representing input and output lines using expressions.

This enters an expression into the subsidiary Wolfram System session without evaluating it:

LinkWrite[link,Unevaluated[EnterExpressionPacket[Factor[x^6-1]]]]

Here are the next 3 packets that come back from the subsidiary Wolfram System session:

Table[LinkRead[link],{3}]

(RefLink[InputNamePacket, paclet:ref/InputNamePacket]) and (RefLink[OutputNamePacket, paclet:ref/OutputNamePacket]) packets are often convenient for making it possible to tell the current state of a subsidiary Wolfram System session. But you can suppress the generation of these packets by calling the subsidiary Wolfram System session with a string such as "math -mathlink -batchoutput".

Even if you suppress the explicit generation of (RefLink[InputNamePacket, paclet:ref/InputNamePacket]) and (RefLink[OutputNamePacket, paclet:ref/OutputNamePacket]) packets, the Wolfram System will still process any input that you give with (RefLink[EnterTextPacket, paclet:ref/EnterTextPacket]) or (RefLink[EnterExpressionPacket, paclet:ref/EnterExpressionPacket]) as if you were entering an input line. This means for example that the Wolfram Language will call (RefLink[$Pre, paclet:ref/$Pre]) and (RefLink[$Post, paclet:ref/$Post]), and will assign values to (RefLink[In, paclet:ref/In])[(RefLink[$Line, paclet:ref/$Line])] and (RefLink[Out, paclet:ref/Out])[(RefLink[$Line, paclet:ref/$Line])].

Evaluating expressions without explicit input and output lines.

This sends an (RefLink[EvaluatePacket, paclet:ref/EvaluatePacket]). The (RefLink[Unevaluated, paclet:ref/Unevaluated]) prevents evaluation before the packet is sent:

LinkWrite[link,Unevaluated[EvaluatePacket[10!]]]

The result is a pure (RefLink[ReturnPacket, paclet:ref/ReturnPacket]):

LinkRead[link]

This sends an (RefLink[EvaluatePacket, paclet:ref/EvaluatePacket]) requesting evaluation of (RefLink[Print, paclet:ref/Print])[x]:

LinkWrite[link,Unevaluated[EvaluatePacket[Print[x]]]]

The first packet to come back is a (RefLink[TextPacket, paclet:ref/TextPacket]) representing text generated by the (RefLink[Print, paclet:ref/Print]):

LinkRead[link]

After that, the actual result of the (RefLink[Print, paclet:ref/Print]) is returned:

LinkRead[link]

In most cases, it is reasonable to assume that sending an (RefLink[EvaluatePacket, paclet:ref/EvaluatePacket]) to the Wolfram System will simply cause the Wolfram System to do a computation and to return various other packets, ending with a (RefLink[ReturnPacket, paclet:ref/ReturnPacket]). However, if the computation involves a function like (RefLink[Input, paclet:ref/Input]), then the Wolfram System will have to request additional input before it can proceed with the computation.

This sends a packet whose evaluation involves an (RefLink[Input, paclet:ref/Input]) function:

LinkWrite[link,Unevaluated[EvaluatePacket[2+Input["data ="]]]]

What comes back is an (RefLink[InputPacket, paclet:ref/InputPacket]), which indicates that further input is required:

LinkRead[link]

There is nothing more to be read on the link at this point:

LinkReadyQ[link]

This enters more input:

LinkWrite[link,EnterTextPacket["x + y"]]

Now the (RefLink[Input, paclet:ref/Input]) function can be evaluated, and a (RefLink[ReturnPacket, paclet:ref/ReturnPacket]) is generated:

LinkRead[link]

Interrupting a WSTP-compatible program.

This sends a very time-consuming calculation to the subsidiary process:

LinkWrite[link,EnterTextPacket["FactorInteger[2^777-1]"]]

The calculation is still going on:

LinkReadyQ[link]

This sends an interrupt:

LinkInterrupt[link]

Now the subsidiary process has stopped and is sending back an interrupt menu:

LinkRead[link]

This closes the link:

LinkClose[link]