Misty Programming Language:Programs

Misty has direct support for actors. Actors run independently and concurrently. Actors communicate by sending messages. Every actor has its own memory space. Actors do not share memory. Every actor runs an executable. An executable is made from a program, zero or more modules, and a build specification.

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

A program can use modules. Many programs can work productively together.

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

misty_type "program" "module"

Every program has an actor object called @at sign that contains the private address of the actor itself and other powerful capabilities. An actor can pass actor address objects (including an attenuated version of @) as inputs to functions or in messages to other actors. If an actor can acquire the actor address object of another actor, then it can send messages to it. Messages may contain numbers, texts, records, arrays, logicals, blobs, and actor address objects.

An attenuated @ object is produced when @ is on the right side of an assign statement, or when @ is passed an input value to a function, or when @ is included in an array literal or record literal. An attenuated @ object contains the private address of the actor.

Misty programs are organized into source files. There are two types of Misty source files:

A module is a chunk of independent program. 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.

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.

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 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 also contain use statements. It is possible that two or more use statements might reference the same module. Should this occur, the module is executed once. A single stone module product is shared by all uses.

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 imports 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.

Messages are usually transmitted over some sort of connection.

The name of a program or module can contain an endowment of values provided at the time the program is built. So if the example program is endowed with a superpower, the superpower can be accessed as example.superpower.

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.

Process 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. Process 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.

Example:

actor?(@)                         # true
actor?(my_process)                # true
record?(my_process)               # false
stone?(my_process)                # true
my_process = my_process           # true
my_process = your_process         # false (probably)

The actor? function

actor?(value)

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

Process lifecycle

An actor is created by another actor by @.start(program) which returns 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 may 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.

@at sign Functions

The @ object is only available in misty program files. The @ object is not available in misty module files, although the attenuated actor object and some of the @ functions can be passed in.

clock function

@.clock(function)

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

connection function

@.connection(callback, actor, configuration)

The connection function takes a callback function, an actor object, and a configuration record for getting information about the status of a connection to the actor. The configuration record is used to request the sort of information that needs to be communicated. This can include latency, bandwidth, activity, congestion, cost, partitions. The callback is given a record containing the requested information.

contact function

@.contact(callback, record)

The contact function sends a message to a portal on another machine to obtain an actor object.

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 function

@.couple(actor)

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

call @.couple(patron)

delay function

@.delay(function, seconds)

The delay function is used to schedule the invocation of a function at a later time. Any value returned from the delayed invocation is ignored. There is no guarantee that the function 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 delay function returns null.

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

The seconds input speicifies 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.

call @.delay(continuation, 0.1) 

portal function

@.portal(function, 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 object. The function will receive the record containing the request. The record can have a reply sent through it. A portal can respond by beginning 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.

random functions

@.random()

The random function returns a number between 0 and 1. There is a 50% chance that the result is less than 0.5.

@.random_fit()

The random_fit function returns an integer in the range -36028797018963968 thru 36028797018963967 that contains 56 random bits. See fit.

receiver function

@.receiver(function)

The receiver function registers a function 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 function

@.start(callback, program, arguments)

The start function creates a new actor. 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 arguments array contains up to four arguments of type logical, number, text, or actor address object.

The current actor is the overling of the new actor, and it is notified when the new actor stops. The new actor is an underling of the current actor.

Example:

call @.start(
    callback
    "example.mst"
)

stop function

@.stop(actor)

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

unneeded function

@.unneeded(function, seconds)

The unneeded function registers a function that is called when the actor that it 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 befire it is stopped.

The unneeded function returns null.

Process Data Structures

Process Address Object

An actor 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

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 fragment of time called a turn. A turn starts with the receiving of a message. A function (such as the function registered with @.receive, @.greeter, @.clock, or a delay callback function) will run to completion. Any outgoing messages are held until the turn completes successfully, at which time they go into the outgoing 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

The name of a program or module can contain endowed constants. These constants can be used to customize a program. The constants are accessed by the .period operator. The endowment constants can be specified when the program executable is produced.

An endowment can also contain functions that give access to system powers will I/O. See Policy.

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

Logging

A log service is built into Misty for the chronicalling of errors and and mishaps. See the log statement.

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.