final class TimeSpec[T] (number : Long, action : Long => T) {
def nanoseconds = action (number)
def microseconds = action (number * 1000L)
def miliseconds = action (number * 1000L * 1000L)
def seconds = action (number * 1000L * 1000L * 1000L)
def minutes = action (number * 1000L * 1000L * 1000L * 60L)
def hours = action (number * 1000L * 1000L * 1000L * 60L * 60L)
def days = action (number * 1000L * 1000L * 1000L * 60L * 60L * 24L)
}
final class Trigger (actor : MyActor, payload : Any) {
def in (number : Long) = new TimeSpec[Unit] (number, scheduleIn)
def every (number : Long) = new TimeSpec[Unit] (number, scheduleEvery)
private def scheduleIn (nanos : Long) = Scheduler.inNano (actor, payload, nanos)
private def scheduleEvery (nanos : Long) = Scheduler.everyNano (actor, payload, nanos)
}
final class ActorSchedule (actor : MyActor) {
def payload (payload : Any) = new Trigger (actor, payload)
}
trait MyActor ..... {
protected val schedule = new ActorSchedule (this)
....
}
This code made it possible to schedule messages in a natural way, like:
object TestActor extends MyActor {
schedule payload `Hi in 10 nanoseconds
schedule payload `HowAreYou every 5 seconds
schedule payload `Bye in 5 days
def act () = {
case `Hi => println ("Hello!")
case `HowAreYou => println ("I am fine")
case `Bye => println ("Bye-bye")
}
}
The idea is that schedule is an object of class ActorSchedule. This class has method payload which takes a payload object as its argument. So "schedule payload `Hi" is actually an invocation "schedule.payload(`Hi)". This invocation will create an object of class Trigger. Trigger class has two public methods - in(Long) and every(Long). Because we cannot do anything until a time unit is given, we create an object of TimeSpec class passing to it a method (scheduleIn or scheduleEvery) that is to be run with number of nanoseconds when one of TimeSpec's methods is called. I think this API is concise enough with only small efforts taken to implement it.