|
|
# AmbientTalk explained by means of a few example code snippets
|
|
|
|
|
|
This page lists some of AmbientTalk's most characteristic expressions, showing how the language aids the programmer in writing applications for distributed computing.
|
|
|
|
|
|
# Remote Communication
|
|
|
|
|
|
Here is how to send a message to a remote object, receive a reply, and deal with the exception that the reply was not received in time:
|
|
|
|
|
|
```
|
|
|
import /.at.lang.futures;
|
|
|
|
|
|
when: shop<-checkout(cart)@Due(seconds(20)) becomes: { |answer|
|
|
|
// code to execute when the checkout message was successfully received.
|
|
|
// answer refers to the return value of the checkout method of the remote shop object.
|
|
|
} catch: TimeoutException using: { |e|
|
|
|
// code to execute when the shop object did not respond before 20 seconds
|
|
|
// note: this block may be executed either because the message checkout
|
|
|
// could not be sent or was not succesfully acknowledged, or because the message
|
|
|
// carrying the reply was not received, or has not yet been received (missed the deadline)
|
|
|
}
|
|
|
```
|
|
|
|
|
|
The expression `obj<-msg()` denotes an *asynchronous* message send. The `@Due` annotation puts a timeout on this asynchronous send.
|
|
|
|
|
|
# Discovery
|
|
|
|
|
|
To make an object available to other actors in the ad hoc network, execute:
|
|
|
|
|
|
```
|
|
|
def pub := export: obj as: Type;
|
|
|
```
|
|
|
|
|
|
where `obj` is the object to be exported, and `Type` refers to a type tag by means of which the object can be discovered. To unexport the object, execute `pub.cancel()`. Here's how to discover the object:
|
|
|
|
|
|
```
|
|
|
def sub := when: Type discovered: { |obj|
|
|
|
...
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Here, `obj` is either a far reference to the object (i.e. a remote object reference) if `obj` is pass-by-reference, or a copy of the object, if `obj` is pass-by-copy. To stop looking for a `Type` object in the ad hoc network, invoke `sub.cancel()`.
|
|
|
|
|
|
The above block is triggered upon discovering one object of the appropriate (sub)type. If one wants to trigger a block every time an object of the appropriate type is discovered, execute:
|
|
|
```
|
|
|
whenever: Type discovered: { |obj|
|
|
|
...
|
|
|
}
|
|
|
```
|
|
|
|
|
|
# Failure Detection
|
|
|
|
|
|
Given a far reference `ref` to a remote object, here's how to use AmbientTalk's built in failure detector to react to the object going offline:
|
|
|
|
|
|
```
|
|
|
def sub := when: ref disconnected: {
|
|
|
...
|
|
|
}
|
|
|
```
|
|
|
|
|
|
And here is how to react to the object becoming available again:
|
|
|
|
|
|
```
|
|
|
def sub := when: ref reconnected: {
|
|
|
...
|
|
|
}
|
|
|
```
|
|
|
|
|
|
In both cases, `sub` refers to a subscription object. Invoking `sub.cancel()` cancels the subscription of the block with the far reference, after which it will not be invoked anymore until the block is explicitly re-registered.
|
|
|
|
|
|
In both of the above cases, the block is fired only once. If the block must be fired every time a disconnection/reconnection occurs, use the `whenever:disconnected:` and `whenever:reconnected:` variants.
|
|
|
|
|
|
# Leasing
|
|
|
|
|
|
Here's how to create a lease for an object:
|
|
|
|
|
|
```
|
|
|
import /.at.lang.leasedrefs;
|
|
|
|
|
|
def l := lease: minutes(10) for: obj;
|
|
|
```
|
|
|
|
|
|
Here, `l` is a leased reference: a proxy to `obj` which remains valid for at least 10 minutes. Every time a message is sent via the lease to the object, the lease gets transparently renewed. When a lease has expired, it no longer acts as a proxy for `obj`, allowing `obj` to be eventually reclaimed if no other objects refer to it. One can react to the expiration of a lease as follows:
|
|
|
|
|
|
```
|
|
|
when: l expired: { ... }
|
|
|
```
|
|
|
|
|
|
# Timing
|
|
|
|
|
|
Here's how to postpone the execution of a block of code until a certain period of time has elapsed:
|
|
|
|
|
|
```
|
|
|
import /.at.support.timer;
|
|
|
|
|
|
def sub := when: seconds(10) elapsed: {
|
|
|
...
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Here, `sub` refers to a subscription object. Invoking `sub.cancel()` unregisters the block with the timer, such that it will not be executed in the future. If you want to repeatedly execute a block of code, write:
|
|
|
|
|
|
```
|
|
|
whenever: minutes(1) elapsed: {
|
|
|
...
|
|
|
}
|
|
|
``` |