[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

MOPping up [Re: Macros Make Me Mad [Re: Database languages]]

On Monday 18 November 2002 12:41 pm, Neel Krishnaswami wrote:
> In addition to grabbing data from the database, I also needed to put
> the results back into it, and potentially to draw them out again in
> other routines, so I needed two way communication. I also wanted to be
> able to "check in" changes as the program proceeded, so that if there
> was a crash we wouldn't have to restart the whole computation. My
> ideal language would have permitted me to mix both database and
> mathematical operations freely -- I would have really liked having
> something like the Erlangers' mnesia or Noel Walsh's SchemeQL.
> (I should note that it's not SQL itself that I wanted; I wanted easy
> access to the Oracle database, and the syntax was not that important.)

== Data Point ==

I worked on a project where we used adapters to multiple DBs (Oracle, 
SQLServer, PostgressSQL, etc).    We did a 24/7 system for use by fortune 
1000 companies that demanded high reliability (a process typically lives 2..3 
years).  We also required persistent state.  We also did not want to spend 
our time dealing with the various dialects of SQL.

We used Xanalys Common Lisp, including Macros, MOP, and multiple 
inheritance, including "before and after methods".  Now IMHO (coming from a 
Scheme background) macros are over-used in Lisp.  However, in concert with 
other language features, they do make one very much more productive.

Our code tended to look like the following:

(corba:define-method op:activate ((self api-manager) token)
  "Activate the specified object referenced by token."
  (with-safe-return-handler (op:activate self token)
    (with-transaction* ()
      (with-known-object (obj token)
		(activate obj)))
    (operational-constraint-violation (err)
      (error 'BULLSEYE:OperationalConstraintViolation
	              :why (reason err)))))

Each "layer of the union" is separately testable.

>> with-safe-return-handler is a handler-case which throws some well known 
CORBA exceptions when it catches anything weird  (e.g. Unknown, 

>> with-known-object finds the persistent object, and raises UnknownObject if 
not found.

>> with-transaction* ensures atomicity, reverts persistent objects to their 
original state if a transaction fails,  and notifies objects which so desire 
that transaction has been successful.  Transactions can be nested.

This interacted with the DB to implement persistent state for CLOS objects:

(defmethod activate ((self content-space))
  (setf (active? self) t))

(defmethod activate :after ((self content-space))
  (request-successful-transaction-notification self))

(defmethod notify-successful-transaction ((self content-space))
  (walk-over-active-allocators (alloc)
    (op:refresh_content_spaces alloc (list (oid self)))))

We used the MOP and a DEFINE-PERSISTENT-CLASS macro to implement/add the 
requisite mechanics around persistent slots (instance vars).

As the SQL generation was pushed down into a low level of the system, we 
spent our time writing productive Lisp code (which generated SQL as required) 
rather than writing SQL and having to test it on each DB.

It worked very well for us.  

We knew we were winning when we got to the point that we were reducing the 
number of lines of code as we were adding functionality to the system.

[FYI, the Xanalys code was not perfect, but in almost every case (95%+) a 
bug report was answered by a patch the next business day which fixed the 
problem.  I have never before seen this stellar level of support.  It is an 
indicator of the productivity of the technology].

Guy probably knows the quote, but I remember someone once said something like 
"Programming languages should not be designed to keep losers from losing, but 
to help winners win big" [I probably have it wrong, but you get the gist].

Lisp is not a perfect language.  I don't know of a perfect language.  But the 
combination of Closures, Macros, Multiple Inheritance, and MOP do allow (NOT 
guarantee) one to productively write complex, large scale, commercial, fast, 
correct, usable, highly robust software.