Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Coupling two packages via an interface ?

1 view
Skip to first unread message

jurgen_defurne

unread,
Mar 4, 2009, 8:42:17 AM3/4/09
to
In my design I have a front-end and a back-end. The front-end acts
like a command processor, but in CL, instead of a specially written
interpreted language. The front-end controls the back-end. The front-
end is always the same, but the back-end can change. So I am trying to
connect the back-end to the front-end through a common interface.

The interface functions are created in the back-end and always refer
to lexical variables, so I need to return closures. However, there are
several strategies possible.

a) Return a multiple value list of closures and bind them in the front-
end to call them via funcall
b) Return a structure containing these closures and also call them via
funcall
c) export them via the package definition and create them as named
closures in the following fashion

(defun create-closures ()
(let ((a 0))
(values
(defun closure-up ()
(incf a))

(defun closure-down ()
(decf a)))))

Maybe I should even write some glue ? In the current case the front-
end loads the back-end, but maybe I should have a third program which
initialises the back-end, and then initialise the front-end using the
return value from the back-end ?

Regards,

Jurgen

Pascal J. Bourguignon

unread,
Mar 4, 2009, 9:36:00 AM3/4/09
to
jurgen_defurne <jurgen....@pandora.be> writes:

Closures are equivalent to objects.

Why don't you use normal CLOS objects, with classes and subclasses?


(defclass counter ()
((a :initform 0)))

(defmethod counter-up ((self counter))
(incf (slot-value self 'a)))

(defmethod counter-down ((self counter))
(decf (slot-value self 'a)))

(defun create-counter ()
(make-instance 'counter))


(let ((c (create-counter)))
(counter-up c)
(counter-down c))

Then you can easily define "back-end" counters:

(defclass remote-counter (counter)
((host :initform "localhost" :initarg :host :reader host)
(login :initform "counter" :initarg :login :reader login)
(file :initform "~/counter" :initarg :file :reader file)))

(defmethod gen-command ((self remote-counter) operator)
(format nil "ssh \"~A@~A\" bash -c 'counter=$(cat ~S);counter=$(( $counter ~A 1 ));echo $counter>~2:*~S'"
(login self) (host self) (file self) operator))

(defmethod counter-up ((self remote-counter))
(ext:shell (gen-command self "+")))

(defmethod counter-down ((self remote-counter))
(ext:shell (gen-command self "-")))


and write create-counter to select the right backend:

(defun create-counter ()
(ecase *backend*
((:remote)
(make-instance 'remote-counter :host *remote-host* :login *remote-login* :file *remote-file*))
((:local)
(make-instance 'counter))))


For a more complete example, have a look at the sources of swank.

--
__Pascal Bourguignon__

0 new messages