====== Key Expressions ======
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: lightbulb<-toggleLight()@Due(seconds(10)) becomes: { |reply|
// code to execute when the message has been
// succesfully processed.
// reply refers to the return value of the
// toggleLight method.
} catch: TimeoutException using: { |e|
// code to execute when the light bulb did not
// respond before 10 seconds
// note: this block may be executed either because
// the message toggleLight 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|
// code to execute upon discovery
}
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. ''sub'' refers to a subscription object. 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|
// code to execute upon every discovery
}
==== 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: {
// code to execute upon disconnection
}
And here is how to react to the object becoming available again:
def sub := when: ref reconnected: {
// code to execute upon reconnection
}
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: {
// code to execute upon lease expiration
}
==== 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: {
// code to execute after 10 seconds
}
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: {
// code to execute every minute
}