[Gambas-user] Inheritance and Signature checking in gambas 3

Bruce Bruen bbruen at ...2308...
Tue Sep 20 02:26:13 CEST 2011


HI,

I thought I may have trouble with this area :-(

I am migrating quite a lot of gambas2 components that work well and most
of the pain has arisen in this signature checking in the runtime, as in
the "incorrectly overridden" message.

First, because this is only evident in the runtime, I have a fear that
testing the converted components may miss the error when the override is
in a rarely executed area of code.

Secondly, I can no longer override a method declared in a base class as
Identifier(...) with a method in the child class with a real and
restricted parameter set. To explain, I have a set of base classes in
component X that provide the very fundamental features of an inheritance
hierarchy.  As well, they prescribe a set of methods that must be
implemented in the child classes.  In short, they are "stubs" for
required methods.  All they do is raise an error if the method is not
overridden in the child class.  Because of this, these stubs have no
idea nor do they care what the parameters of the child class method are.

As an example, I have a persistence model that involves three levels of
code: 
the [application] ----uses---> [a business_object library]
---inherits---> [base_persistence]
The persistence of the data is entirely handled by the two lower level
libraries, the application only has to call the Create, Read, Update or
Delete methods on the business_object object and all it's persistence
needs are handled.  The business_object library contains all the
relevant business rules for its classes, e.g. whether objects can be
deleted from the persistence or whether a cascaded delete is necessary
etc etc.  However, the business_object layer has no idea exactly how the
persistence is achieved, it just validates the action applies the
relevant transformations between the object data model and the
persistence data model and then passes the object data off to the low
level persistence methods in it's parent class.  This is the high level
design.

The implementation employs the following code model:  at the
business_object library level, each business object has (at least) two
classes, the main object class, e.g. "Account" and one or more mapping
classes, say "_sqlaccount" and "_xmlaccount".   The main class is
visible to the application, the mapping classes are hidden.  The mapping
classes provide the two way transformation between the object data and
the persistence data,  in short they have a "Marshall" method and an
"Unmarshall" method.  These two methods are very importantly "visible"
to the base_persistence library.

The last comment requires explanation.  In the base_persistence library
there is a similar split between the "object" model and the
"persistence" model.  There is a base "BusinessObject" class, from which
all the classes in the business_object library inherit, and a base
"persistor" from which all the mapping classes in the business_object
library inherit.  (There is a tricky bit here that is important to the
design but irrelevant to this message - there is a base persistor for
each persistance type, e.g. postgresql, mysql, xml, flatfile etc.  Each
of these is in separate libraries and is loaded explicitly at runtime by
the BusinessObject class depending on the settings file for the
business_object library. Suffice to say that it is the actual base
persistor that provides the actual input/output methods to "add",
"load", "save" and "remove" the data. Note the change from the CRUD
method names!)

When the application instantiates a business object, say an Account
object called "MyAccount", the constructor in the base_persistence
library BusinessObject class i.e. BusinessObject._new() checks the
persistence method in use and instantiates the relevant mapping class in
the business_object library, i.e. it creates an actual persistor which
is either a "_sqlaccount" or an "_xmlaccount".  How I do this is
irrelevant, the important thing is that the BusinessObject has access
to, via the gambas virtual dispatching feature, one of these things
which as far as it is concerned is a "persistor".

The CRUD methods are actually public in the BusinessObject class, i.e.
they are inherited by the classes in the business object library.  So
when the application does a "MyAccount.Update, it is actually calling
the BusinessObject.Update method.  This in turn calls its'
persistor.save method.  In fact, what it does is call its'
persistor.Marshall method and then its' persistor.save method.  Note the
subtle inference here, the Marshall method is the the one in the active
mapping class and the save method is the one in the base persistor class
(there is no save method in the mapping class). However, in order to
compile the base_persistence libraries there must be a "stub" method
called "Marshall" at this level and this is the one that MUST be
overridden at the higher level.  Further, at this level (in the base
persistor libraries) I have no idea as to how the business_object
library level "Marshall" method works, nor what parameters it needs to
achieve that work - that is a matter for the specialised classes and the
BusinessObject class.  All I know is that the method must be declared
and it must be overridden, so it is:

Public Sub Marshall(...) 
    Error.Raise("Implementation fault - this method must be overridden
in the business_object library")
End

I hope you have managed to follow all this and can offer some advice.
The persistence architecture model is not my own invention, it comes
from work by Fowler and others.  It has worked for me for the last two
years in gambas2 and (the code) is the result of significant!!! effort
on my part.  I just can't see a solution now with this signature
checking in the gambas3 runtime.

Finally, I still can't see the value in this signature checking.  This
is only one area where I have successfully used method overrides in
gambas2 which now have to be not only rewritten but redesigned for
gambas3.  Why was it introduced?  If it is really necessary for
something else then I'd like to ask for a way to turn it off, preferably
at the gbx3 compile, not only for signature checking but also for result
type checking.

regards
Bruce  




More information about the User mailing list