====== 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 }