|
Lambic by example |
Note: This section, as the complete Lambic website, is still under heavy development and therefore it will be frequently updated. |
|
Lambic extends the Common Lisp Object System (CLOS) with the notions of futurised multimethods and method dispatch with context predicates. Each of these features is explained by means of simple examples. |
|
We have used Lambic to develop a non-trivial scenario of a distributed graphical editor, called Geuze. This editor can be used in different hosts to work collaboratively on a same graphical document. The description and implementation of Geuze can be found here. |
|
In Lambic, as in Common Lisp, classes indicate the type and state (fields) of the objects. |
(defclass instant-messenger ()
(username :initarg :username :accessor im-username)) |
|
Methods are independent of classes, grouped in generic functions. |
(defgeneric receive-text (receiver sender text)) |
|
Method selection is based on the classes of the arguments. |
(defmethod receive-text ((receiver instant-messenger)
sender text) (display-text receiver sender text) (store-text receiver sender text)) |
|
|
In Lambic proposes a model that alleviates the restrictions of predicate dispatch to cope with method overriding ambiguities. Instead of requiring logical implication order between predicates, this model fosters the definition of context-specific priorities. Predicated generic functions enable users to establish a priority order between logically unrelated predicates. These priorities are specified in a per-generic-function basis: predicated generic functions contain not only the methods with a common name and argument structure (as in standard generic function models), but also the predicates on which such methods can me specialised. A method is applicable when its predicate expression evaluates to true, and the order of the predicates specified in a generic function determines the order of applicability of its methods.
Consider as illustrative example the factorial function. In this function we want to distinguish between negative and positive numbers, and the number zero. We therefore define a factorial generic function using as predicates the functions for aritmethic comparison <, =, and > (using the :predicates keyword) . Since these are already defined in Common Lisp, we just need to declare them as predicates for the factorial generic function, indicating the corresponding symbols as follows: |
(defgeneric factorial (n) (:predicates '< '= '>)) |
|
We can now define methods for this generic function: |
(defmethod factorial (n) (:when (> n 0)) (* n (factorial (- n 1))))
(defmethod factorial (n) (:when (= n 0)) 1)
(defmethod factorial (n) (:when (< n 0)) (error "Factorial not defined for negative numbers.")) |
|
Each of these methods indicates one of the predicates declared in the generic function using the :when keyword. The first method is called if the argument n is a positive number and computes the general case of the factorial function. The second method is called if n is 0 and returns 1. The third method will be called if n is a negative number and signals an error. |
|
Consider as example a drawing editor -called Geuze- provided with a number of operations for drawing, moving, resizing and painting shapes. In a pervasive computing environment, Geuze enables its users to spontaneously create sessions for sharing and editing each other's shapes in a common canvas. In this case, the operations a user performs are propagated to the rest of the participants of the session. The collaboration in Geuze is also influenced by the context in which it occurs. For instance, to keep a consistent drawing in the different session's editors, Geuze can provide means to constrain the edition of a shape to only one user at the time, and to react to the disconnection of the participants, e.g. by blocking or hiding the disconnected participant's shapes.
The current prototyipical implementation of Geuze can be found here. |
|