Misty Programming Language:

Actors

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. A program is generally a lead actor that may be assisted by a team of supporting actors running in the same machine or in different machines. An actor may make use of modules.

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

misty_type "actor" "module"

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

An attenuated @ object is produced when @ is on the right side of a set statement, or when @ is passed an argument to a function, or when @ is included in an array literal or record literal. An atenuated @ 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 may not include if or 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. An actor file does not end with a return statement.

When an actor is started, the statements in the actor 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 actor can pull in code from the module library by use of the use statement. A module executes its body, as a function does, and returns a value that will be bound to the name in the use staement. Typically, it will return a constructor function, but it can also return a record of functions. The value returned by a module will be 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 will be executed once, and all of the use statements referencing that module will bind the same value. If two actors reference the same module, the module will be executed for each actor. Actors do not share modules with way module do.

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

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

misty actor example

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

end example

Actors are started with the @.new method. An actor that starts another actor is called a master. An actor started by a master is called a padawan. An actor can be a padawan to one actor and a master to many others.

Communication between actors happens exclusively with messages. Messages are one-way with eventual consequences.

Messages are usually transmitted over some sort of connection.

Actor object

An actor 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 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 object. Actor objects can be sent to other actors, giving them the capability to also send messages to the actor associated with the actor object.

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

Example:

actor?(@)                     # true
actor?(my_actor)              # true
record?(my_actor)             # false
stone?(my_actor)              # true
my_actor = my_actor           # true
my_actor = your_actor         # false (probably)

The actor? function

actor?(value)

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

Actor lifecycle

An actor is created by another actor by @.new() and in that act of creation may be given private addresses. Over its life, an actor will receive messages, which may cause it to change its state and send messages.

Ultimately, there are three ways that an actor dies:

Dignity

An actor dies with dignity when it calles @.die(). It may do this as a result of being told to do so by its master or another trusted actor, or because it has fulfilled its purpose. Any messages sent in the final turn will be put into the outgoing queue.

Disrupt

If an actor dies from an unhandled disrupt, then it is terminated. Any messages sent in the final turn will not be put into the outgoing queue.

Murder

An actor may be killed violently by its master. If the actor is executing a turn at the time of death, any messages sent in the final turn will not be put into the outgoing queue.

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 kill message, which, if valid, will cause an actor to immediately die, 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.

receiver function

The receiver method is given a callback function that will receive the actor's messages. The callback function will receive a single argument, the message object. The callback function will not be given reply messages.

@ Methods

The @ object is only available in the misty actor files. The @ object is not available in misty module files, although the attenuated actor object and some of the @ methods can be passed in. The @ object may contain these methods: clock, connection, contact,die, garbage, kill, new, pact, portal, random, random_bits, receiver.

clock method

@.clock(function)

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

connection method

@.connection(callback, actor, configuration)

The connection method 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 will be given a record containing the requested information.

contact method

@.contact(callback, record)

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

The record can contain:

die method

@.die()

This method ends the actor with dignity. Any messages sent in this final turn will be put into the outgoing queue.

garbage method

@.garbage(function)

This method registers a function that will receive a message informing the actor that it has probably become unreachable and useless. The actor should put its affairs in order and then @.die() with dignity.

kill method

@.kill(actor)

This method murders the actor even if it is in the middle of a turn. The actor object must be one of your own padawans.

new method

@.new(callback, text, configuration)

The new function creates a new actor. It takes a text that identifies the actor program file that the new actor runs. The text locates an actor program in the actor section of the misty module database.

The configuration record contains fields having the names of the @ methods. If the field's value is true, then the new actor will have that method in its own @ object. So, if the configuration contains a contact field that is true, then the new actor is allowed to contact portals to obtain actor objects. However, if the master does not have access to the method itself, it can not make it available to the padewan.

The callback function will be passed the padawan actor object.

The current actor is the parent of the new actor, and it will be notified when the new actor terminates.

Example:

call @.new(
    callback
    "example.mst"
    {
        contact: true
        new: true
        pact: true
        receiver: true
    }
)

portal method

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

random functions

@.random()

The random function returns a number between 0 and 1.

@.random_bits()

The random_bits function returns a signed whole number in the range -36028797018963968 thru 36028797018963967 that contains 56 random bits.

receiver method

@.receiver(function)

This method registers a function that will receive all messages sent to the actor except for portal contact messages, and replies.

Actor Data Structures

Actor Object

An actor object is used with the send statement. It contains an actor's private address. A message may contain actor 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 may be used 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 delivery of a message. A function (such as the function registered with @.receive, @.portal, @.clock, or a delay callback function) will run to completion. Any outgoing messages will be 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.

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.

Guests

Logging