EScala | EScala as a library

Introduction

EScala can be used as a standard Scala library. This section shows examples on how to use the library with an unmodified version of the language. A complete example is available for download in the Download section.

The event library classes are all in the events.lib package.

Event declaration

All the event are a subtype of events.lib.Event[T].

Events are declared as values

import events.lib._

class Figure {
lazy val changed = new ImperativeEvent[Unit]
}

This declares an imperative event which takes Unit as parameter, i.e. no parameter. This event can be explicitly triggered in the code as a method call.

val f = new Figure
// trigger the changed event
f.changed()

Events can also be combined together using the combinator methods available in the Event trait

class Figure {
// event emitting two integers
lazy val figureMoved = new ImperativeEvent[(Int, Int)]
// event emitting an integer
lazy val colorChanged = new ImperativeEvent[Int]
// disjunction of both previously declared events
// parameters are dropped to unify the event types
lazy val changed: Event[Unit] = figureMoved.dropParam || colorChanged.dropParam
}

Some of the available combinators are

  • Events disjunction e1 || e2
    Both event types must be compatible.
  • Events conjunction e1 && e2
    Event types are merged to a pair.
  • Event filter e && predicate
    predicate is a method returning a boolean. The resulting event matches only if teh event was triggered and the predicate was true.
  • Parameter mapping e.map(transformation)
    It allows to map the value provided by the event to an other type or value. The resulting event parameter has for type the return type of the transformation method
  • Parameter droping e.dropParam
    Equivalent to the map operator with a transformation method doing nothing and returning Unit

Reactions registration

Reactions can be registered to an event by using the += operator

class Figure {

def reaction() {
// react to the event
}
changed += reaction

The reaction must take as parameter the value provided by the observed event.

It is also possible to deregister a reaction using the -= operator. In this case the reaction method must be declared as lazy value.

class Figure {

lazy val reaction = () => {
// do something
}
changed += reaction
def undeploy {
changed -= reaction
}
}

Variable references

The library provides two utility classes allowing to reference events of mutable variables

  • Variable[T] wraps a variable of type T. It notifies the changes of the reference through a changed event. It also provides an event operator which takes a function computing an event from the wrapped object as parameter and returns the event depending on the object.
  • VarList[T] is an observable list. It provides a method any which aggregates the events of the elements in the list, described by a function passed as parameter. The list observes changes in its content, which allows to aggregate the events of its current elements.

Observable methods

Implicit events can be observed by lifting a method to make it observable

class Figure {
lazy val moveBy = Observable((dx: Int, dy: Int) => {
// move the figure
})
}

Such a lifted methods exposes then two implicit events named before and after which are triggered before reps. after the method call. They can be used to declare more complex events.

class Figure {
lazy val figureMoved: Event[(Int, Int)]= moveBy.after
}

Implicit conversions

The event library contains an object named EventsLibConversions providing useful implicit conversions. Among others it provides following conversion

  • Wrapping an object of type T into an object of type Variable[T]
  • Converting a Function1[T,R] object to a corresponding Observable[T,R] object
  • Converting a FunctionN object to the corresponding tupled function or a Function0[R] object to the corresponding Function1[Unit, R] object.