Overview
Packets in ADAPT can be either:
- A node-level packet stored inside an ADAPT node.
- A nested packet used as a data item managed by MUFL code, on par with dictionaries and integers.
Much like with node-level packets, nested packets require use of a MUFL application to define state transitions of the nested packet. Subsequent to initializing a nested packet with a MUFL application, your code invokes state transitions by calling the nested packet’s transactions. Invoking transactions causes creation of a new nested packet, representing the new state.
The purpose of nested packets is to enable several ADAPT nodes to share state in a well-defined way. For example, in a series of peer-to-peer card games, the common pot of prize money could be represented as a nested packet. This nested packet would record the outcomes of each subsequent card game.
Creating Nested Packets
You create nested packets using the new database
packet initialization statement.
Consider an ADAPT application sub
:
application sub uses transactions
{
trn do_it
_: ($field->value: any)
{
_print value.
}
}
For a script, application, or library to construct a nested packet, it must load application sub
:
// 'sub' represents the externally-defined application to use to initialize the new packet
script loads application sub {
seriesID = _new_id "42". // provide a unique salt value that ensures that the packet is distinct from all other packets initialized using the application 'sub'.
D = new database sub (seriesID). // initialize a nested packet assigned to variable 'D'
The
_new_id
function generates a 32-byte salt value by invoking the packet’s internal random number generator, mixing in the argument.
Execution of the new database
statement creates the nested packet in an initial state that is ready to receive transaction requests. Once the nested packet is created, you pass initial parameters to the nested packet by invoking a transaction using the transact
statement, as described in the next section.
Invoking Transactions on a Nested Packet
Transactions defined in the packet interface of the nested packet are invoked by MUFL code. Each transaction invocation creates a new nested packet containing the new state. You invoke a nested packet’s transactions using the transact
statement.
The general form of the transact
statement is:
transact <prev_state> [into <new_state>] [result <result_pattern>] [error {fail|<error_var>}] msg <expression>
where:
<prev_state>
is an expression that produces a value of thePACKET
domain.<new_state>
is a name of a variable to be initialized with the new state that results from running the transaction.<result_pattern>
is a pattern destructuring of the transaction output (in the simplest case, a name that takes the output value).<error_var>
is the name to be assigned to the error information, if the state transition fails. A special formerror fail
is used to indicate that if the nested packet transaction fails, then the current transaction should also fail (an error is propagated upwards in the transaction stack).<expression>
is the transaction to invoke in the nested packet in the form($name-><transaction_name>, $targ-><transaction_argument>)
.
Along with <prev_state>
and msg <expression>
, at least one of the into <new_state>
, result <result_pattern>
, or error {fail|<error_var>}
options is required.
For example:
transact D // Invoke transaction on packet assigned to 'D'
into Y1 // Place the new state of the packet into 'Y1'
msg ($name->"::sub::do_it", $targ->($field->55)). // Send message to the nested packet.
Invoking this transaction prints:
55
Transaction Return Values
In the example, the transaction do_it
in application sub
does not return a value (or rather, by not explicitly defining a return value, it returns NIL
implicitly). However, nested packet transactions may produce output values, in addition to output state.
Unlike node-level packets, for which the result convention is defined by the ADAPT framework, you define your own interface to return results from nested packet transactions. The output value (the value that was supplied to the return
statement inside a transaction) can be captured into the result_pattern
value of the result
clause of the transact
statement.