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 the PACKET 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 form error 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.