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

Dylan & object/relational mapping



OK, having thought it through and digested the feedback, my conclusion
is that it is _not_ practical to pursue an EOF-like design in Dylan.
Maybe Dylan will evolve to support that, and maybe not. But right now I
need a different design alternative.

Revisiting the criteria I stated earlier:

1) I _require_ that a solution not involve any per-entity class or code
(whether or not auto-generated) for plain access to entity attributes.

2) I _require_ that this automagically provided access take a syntactic
form identical to that for custom-coded accessors.

3) I would really really really like those accessors to take the
syntactic form identical to regular slot access.

4) It would be nice if the custom classes and accessors were defined
using normal syntax. But it would only be a very minor flaw if these
classes and accessors required special syntax (a special define macro)
for their definitions.

It is clear that 1 & 3 are not compatible in Dylan. So the question
becomes which is more objectionable?

1) Have some kind of automatic code generation.

2) Access attributes via some kind of special syntax, like
db-object.get(#"some-attribute"), or a collection protocol to get
db-object[#"some-attribute"].

Having had a night to reflect on my posts, I've realized that it may not
be the that the _idea_ of code generation is all bad, it may just be
that all implementations that I've seen suck. The reason for this is
just plain poor design. The generated code and custom code are always
entangled in inappropriate ways. 

There are systems that generate an abstract base class and the skeleton
of a derived concrete class. Then regeneration just replaces the base
class and leaves the concrete class alone. This does greatly reduce the
intertwining of generated and custom code. But both such systems that
I've used had flaws that required me to edit the auto-generated base
classes, which of course leads to miserable maintenance issues.

So perhaps a _good_ design could avoid this? It certainly seems that
way.

In fact, since Dylan separates methods and classes we're not necessarily
even talking about auto-gen'ing classes. Maybe just auto-gen'ing
accessor generic functions and methods would be enough. It would
certainly be enough to meet the goals I've been talking about. The
question is whether or not some other piece of the object/relational
mapping would require custom classes to be generated for "plain"
entities without custom behavior. Actually, again that separation of
methods from classes helps. Some limited custom functionality could be
implemented without custom classes. (Another subject perhaps, is whether
or not this would be a _good_ idea.)

And really, for accessors I think it's not even necessary to auto-gen
gfs or methods. It could just be macros that are auto-gen'd; I'm
assuming that I could create a macro (or macros) that would correctly
expand all the forms of a getter (and setter) call to a function call of
my choosing.

As for the other alternative, special syntax for accessing database
attributes, the problem is the distinction between regular slots and
"slots" for these attributes. Sometimes a value may change between being
stored in the database, and being calculated or stored as a class slot.
This change should not be visible to clients. It would be possible to
customize a class so that "attribute" access syntax got redirected to
some slot or calculated value. But this would require that the
possibility be anticipated, so that all such accesses by clients start
with "attributes" syntax. That's ugly enough to make me prefer code
generation ;-) Not to mention just the basic problem of mixing two
different access styles in the same code.

Really, the fundamental point of doing an object/relation mapping layer
is to allow one to write client code in terms of "native" language class
instances and slots, not in terms of rows and columns, or entities and
attributes. I am adding another goal, that of requiring as little
per-entity code as possible, IOW most normal behavior is derived
directly from the database metadata without boilerplate per-entity code,
and only code is created for custom behavior. Maybe that goal has to
bend to allow some boilerplate code to be auto-generated.



Follow-Ups: