Misty Programming Language:Programs

Misty has direct support for the Actor Model of Computation. Actors run executable programs independently and concurrently. Actors communicate by sending messages. An executable is made from a program source text, and zero or more module source texts. Every actor has its own memory space. Actors can interact with actors on other machines. Actors do not share memory with other actors.

The first word of a Misty source is misty, declaring that the source is written in Misty.

The second word of a Misty source is the type, either program or module.

The third word is the title of the source text. This might be the same as its filename in systems that use filenames. The name is used for documentation.

misty "misty" space misty_type space title input_list more_statements linebreak "end" space title

misty_type "program" "module"

title name

Hello world:
misty program hello_world()
log console: "Hello, World!"
end hello_world

A misty program contains the entry point for an executable.

When an actor is started, the statements in the program file are executed. The statements should start the execution of the actor, which usually involves the setting of a receiver so that the actor can receive messages. Other sorts of initialization may take place as well.

The program can pull in code from the module library with the use statement.

A module is a subprogram that provides functionality to a program or other modules. These can be used to build reusable libraries. The body of the module contains a string of statements. The statements in the body may not include do, although a body may contain functions which can include do.

A module executes its body, as a function does, and returns a value that is bound to the name in the use statement. Typically, it will return a constructor function, but it can also return a record of functions. The return value is stone. Modules can be used to protect capabilities. For example, a trusted module might be given access to a block of display memory. The module will be able to modify the pixels. A program using the module will only be able to access the pixels as permitted by the functions that the module provides. Untrusted programs to use trusted modules. If the trusted module is properly constructed, the program can not abuse it.

The last statement in a module is a return statement, which usually returns a function or a record containing functions. That return value is bound to the name in a use statement. A program file does not end with a return statement.

If two actors reference the same module, the module is executed twice. Actors never share memory.

Modules can not have cyclical dependences. Module a can not use module b if module b uses module a.

In this example, the example program uses the app_master_2000 module, and designates its handler function as the receiver of messages for the actor.

misty program example()

use app: "app_master_2000"()
call receiver!(app.handler)

end example

Actors are started with the start!(program) function. An actor that starts another actor is called an overling. An actor started by an overling is called an underling. An actor can be a underling to one actor and an overling to many others.

Communication between actors happens exclusively with messages with the send statement. Messages are usually transmitted over some sort of connection.

A module can have arguments passed to it from a use statement. A program can have arguments passed to it from a command line or start!.

Actor address object

An actor address object contains the information needed to communicate with an actor. An actor object can be transmitted to other actors, even on other machines.

An actor address object is an immutable black box. It can be used in a send statement to send a message to the actor associated with the actor address object. Actor address objects can be sent to other actors, giving them the capability to also send messages to the actor associated with the actor address object.

None of the contents of the actor object are visible or accessible.

A message that can accept a reply can also be used once as an actor address object. See the send statement.

The actor? function

actor?(value)

The actor? function gives true if the value is an actor address object.

Examples:
actor?(me!)                       # true
actor?(overling!)                 # true
actor?(my_process)                # true
record?(my_process)               # false
stone?(my_process)                # true
my_process = my_process           # true
my_process = your_process         # false (probably)

Actor lifecycle

An actor is created by another actor by start!(program) which produces a new private address object. Over its existence, an actor will receive messages, which may cause it to change its state and send messages.

When an actor stops, it will no longer send or receive messages. Ultimately, there are four ways that an actor stops:

Stop

An overling actor may stop a underling by calling stop!(underling). If the underling actor is in the middle of executing a turn when it is stopped, any messages sent in that final turn will not be put into the outgoing queue.

An actor can also stop itself by calling stop!(). It might do this as a result of being told to do so by its overling or another trusted actor, or because it has fulfilled its purpose or become unneeded. Any messages sent in this final turn are put into the outgoing queue.

Disrupt

If an explicit or implicit disrupt occurs that is not handled, then the actor stops. Any messages sent in this final turn will not be put into the outgoing queue.

Coupling

If an actor is coupled to an actor that stops, then it also stops. An actor can couple itself to another actor by calling couple!(actor). Every actor is automatically coupled to its overling.

Disaster

The system crashes, or an earthquake disables the data center, or there is a nuclear sneak attack, or a software bug. Surviving actors will probably not be immediately notified of the disaster.

Messages

Actors communicate using messages only.

Incoming messages are queued by the Misty system and delivered in arrival order. The exceptions are system level messages like the stop message, which, if valid, will cause an actor to immediately stop, even if there are undelivered messages waiting for it in the queue.

Some messages can be used to reply to the original sender of the message.

Actor Data Structures

Actor Address Object

An actor address object is used with the send statement. It contains an actor's private address. A message may contain actor address objects, which will give the recipient actor the capability to send messages to those actors at the private addresses.

There are three ways that an actor can obtain the actor address object of another actor.

Message object

Ordinarily, a message object is obtained from the callback function that is registered with receiver!. It acts like an ordinary record.

When a message is sent using the callback form, the message itself may be used once as an actor's private address for transmitting the reply.

Turns

Computation takes place in an actor in a interval of time called a turn. A turn starts with the receiving of a message. A function (such as the callback function registered with receive!, portal!, clock!, or delay!) will run to completion. Any outgoing messages are held until the turn completes successfully, at which time outgoing messages go into the outgoing message queue and are sent.

An actor will not receive another message until the turn ends. Each turn will process exactly one message.

If a machine has multiple computation units, then it is possible for multiple turns of multiple actors to be going on simultaneously. Turns can be timesliced. There are no concurrency issues because actors do not share memory. They communicate with other actors and the world only by message passing.

Endowment

Programs and modules can be endowed by the Policy Machine with special constants that are identified by names ending in !exclamation mark. Often the values are functions, but they can also be numbers, texts, and actor addresses.

By default, programs and modules may not use the following features. They are only available if specifically allowed by policy.

Time functions

Time is considered a critical capability.

clock!(callback)

The clock! function takes a callback function input value that will eventually be called with the current time in number form in seconds. See time.

delay!(callback, seconds)

The delay! function is used to schedule the invocation of a callback function at a later time. Any value returned from the delayed invocation is ignored. There is no guarantee that the callback will ever be invoked. The delayed invocation will not interrupt normal processing. The invocation is delayed until the actor is waiting for a message.

The seconds argument specifies when the invocation will occur, no sooner than seconds seconds after now. The seconds input must be a non-negative number or null which behaves as 0.

The delay! function immediately returns a cancel function. Calling the cancel function will cancel the delayed execution of the callback, if it is not too late. If it is too late, the cancel is ignored.

Example:
assign cancel_continuation: delay!(continuation, 0.1)

time_limit!(requestor, seconds)

The time_limit! function is a requestor factory that takes a requestor function and returns a similar time limited requestor function, which acts the same, but will automatically cancel when the time is exceeded.

The requestor function returned by time_limit! returns its own cancel function.

Actor functions

The following functions are critical for the implementation of actors.

contact!(callback, record)

The contact! function sends a message to a portal on another machine to obtain an actor object. This is used to bootstrap a distributed actor network.

The callback is a function with a actor input and a reason input. If successful, actor is bound to an actor object. If not successful, actor is null and reason may contain an explanation.

The record can contain:

couple!(actor)

The couple! function causes this actor to stop when another actor stops. The couple function returns null.

call couple!(patron)

portal!(callback, port)

A portal is a special actor with a public address that performs introduction services. It listens on a specified port for contacts by external actors that need to acquire an actor address object. The callback function will receive the record containing the request. The record can have a reply sent through it. A portal can respond by starting a new actor, or finding an existing actor, or by forwarding the contact message to another actor. This is how distributed Misty networks are bootstrapped. The portal function returns null.

receiver!(callback)

The receiver callback function registers a callback that will receive all messages sent to the actor except for delay events, reply messages (which are sent to the send callback), the unneeded message, and portal contact messages. The receiver function returns null.

start!(callback, program)

The start function creates a new actor, aka underling. The callback function receives messages about the new actor, starting with a message containing the new actor's address object.

The program text identifies the executable in the program shop that the new actor runs. The program shop may start an existing executable, or may generate a new executable.

The current actor is the overling of the new actor The new actor is an underling of the current actor. The overling is notified via the callback when the underling stops.

Example:
call start!(
    callback
    "example.mst"
)

stop!(actor)

The stop! function stops an underling. The stop function returns null.

unneeded!(function, seconds)

The unneeded! function registers a function that is called when the actor has not received a message in the recent seconds. The default for seconds is the ar timer. This likely means that the actor is no longer needed. The actor should finish its work and then stop!().

If the unneeded timer is not used, then the ar timer is used by default. The unneeded function allows for setting a longer or shorter time than the ar timer.

This differs from the ar timer in two way: It is optional. Second, the actor is notified by the callback function before it is stopped.

The unneeded function returns null.

Other functions

The Policy Machine can grant access to other functions that access capabilities that are typically associated with operating systems, databases, and cryptographic systems.

Constants

An endowment can provide compile-time constants.

Example:
misty program example
if test!
    # stuff that executes if test! is true
else
    # stuff that execute if test! is false
fi
end example

Failure

Fail to a known condition.

In distributed systems, we can not be certain of failure. Failure may be presumed.

Failure is always an option.