Forum OpenACS Q&A: A doubt about Xotcl Acs objects inheritance

Hello,

I am nicely developing using Xotcl. Today, I've found that when one subclasses ::xo::db::Object, its 'save_new' method ends up calling a method called 'insert'.

This method builds dinamically the proper insert query for a new entry in the database, very nice for new objects. I can redefine my subclass's 'save_new' method adding some specific logic, then just use the 'next' idiom to proceed to the standard logic.

When one is updating an existing object though, this doesn't stand anymore: the save method in ::xo::db::Object doesn't call an analogous 'update' method. The update query is generated instead at startup as a method of my subclass. If I redefine it, then call 'next', my object's table ends up untouched, except for my specific logic that overwrote the original 'save' method.

Is there a particular reason for this different behavior between inserting and updating?

Collapse
Posted by Neophytos Demetriou on
When one is updating an existing object though, this doesn't stand anymore: the save method in ::xo::db::Object doesn't call an analogous 'update' method. The update query is generated instead at startup as a method of my subclass. If I redefine it, then call 'next', my object's table ends up untouched, except for my specific logic that overwrote the original 'save' method.

You are right in the sense that it would have been more convenient to have an extra layer of redirection, i.e. call an analogous update method. When you subclass ::xo::db::Object you can redefine the save method. The only problem I see is that ::xo::db::Class->init can overwrite the save method in the derived class with the one that ::xo::db::Class->mk_save_method generates.

Is there a particular reason for this different behavior between inserting and updating?

The save method that is generated by ::xo::db::Class->mk_save_method calls next within a db_transaction statement (see 05-db-procs.tcl). As the code stands, that next statement invokes ::xo::db::Object->save, which is responsible for inserting the corresponding row in the acs_objects table. This works well for most cases but not when you want to add your own logic to the 'update' method or work outside of the acs_objects system.

Collapse
Posted by Antonio Pisano on
Thanks for the additional insights Neophytos.

Maybe there is space for some discussion about this. I think one should expect generic logic to be inherited when using next, rather than be wiped out by specific method definition.

Here on OpenACS, I think the only class who redefined the save method is CrItem. The method is completely overwritten there, meaning that no use of the 'next' idiom is done. This is becuse CrItems need some really specific behavior to handle revisions and such.

Of course there could be people out there who wrote code with current behavior in mind and used 'next' in their 'save' implementation. If we just turn on inheritance, they will end up with code updating their objects twice... could not be a big deal in the transition phase, yet it's dangerous.

I think this deserves some thinking...

Collapse
Posted by Gustaf Neumann on
Antonio,

in the oacs-type world, it is not possible to subclass an class to provide application specific logic. The mapping was built with notion that all it does is to put a layer over the acs-object system. Application logic can be added in xotcl in many ways, including mixins, etc.

However, you are absolutely right with your observation that mk_save and mk_insert are asymmetrical, it would be better to have a mk_insert and an mk_update. The "save" method should call "update" like the "save-new" method calls "insert".

i've commited this to cvs, it is structurally a simple change and seems to work, and should better fit your use cases.

all the best
-g