[Gambas-user] Inheriting, wrapping and casting

Tobias Boege taboege at ...626...
Sat Apr 19 00:59:03 CEST 2014


On Thu, 17 Apr 2014, Bruno F??lix Rezende Ribeiro wrote:
> Hello Gambas fellows!
> 
> Suppose we are overriding the class 'Variant[]' to add the event
> 'Update' which will be raised after the completion of any method which
> could possibly modify the array structure.  In particular, we need
> to override appropriately any function that happens to do so.  For
> exposition purposes let's consider the 'Extract' function, which removes
> one or more elements from the array and returns them.  It's signature
> is as follow:
> 
>   Public Function Extract(iStart As Integer, \
>     Optional iLength As Integer) As Variant[]
> 
> Our inherited class has, hence, to override this function with another
> of the exact same signature, by Gambas' rules.  However, it doesn't
> make sense to return an object of the base class, while the operation
> is executed by a derived class over an object thereof.
> 
> It seems there is no easy or natural way around it.  We could declare a
> second extraction function for the derived class named after a different
> symbol like "ExtractDerived", but we'd break the interface, what isn't
> a desired outcome.
> 
> Another approach would be to forget this particular base class and go
> upwards until there is no possible conflicting functions and to inherit
> from there, what happens to be in this case the immediate base class of
> 'Variant[]' called "Array".  However, we'd have to re-implement large
> portions of the 'Variant[]' class, that could otherwise be immediately
> deployed if not by our particular design problem at hand.
> 
> One last, and arguably more reasonable, approach is to give up the
> syntactical native language's feature of inheritance --- and its useful
> properties -- and to define a dedicated container base class, which
> inherits from nowhere, semantically wrapping all functionality of the
> class 'Variant[]'.  It'd work as a layer for accessing the underlying
> variant array which would be stored in a private variable and isolated
> from the outside world, i.e., not directly accessible by any property.
> The only way to modify the array's content would be to use the
> class' interface which would mimic that of 'Variant[]'.
> 
> As we've seen, there is no way if not by modifications of the
> interpreter's very core.  Thus, I'd like to know why Gambas enforces
> the signature of functions onwards inherited classes.  If not by
> technical reasons, but only for methodological consistency requirements,
> I'd like to suggest that we make it, at least, allows to use the
> inherited class in place of the parent class within method signatures.
> Personally, I'd find yet more useful if there were no restriction at
> all.
> 
> A very interesting and useful feature, related but independent of this
> suggestion, is that the interpreter could take care of casting objects
> in both directions in an hierarchy of classes.  In order to accomplish
> it, there would be introduced two special methods which would be
> implemented in any class the programmer deems them meaningful and
> useful: '_castUp' and '_castDown', for casting an object from the
> inherited to the parent class, and from the parent to the inherited
> class, respectively.  Being 'ThisClass' the inherited class and
> 'UpClass' its parent, the special methods signatures would be:
> 
> Static Public Function _castUp (hThisClass As ThisClass) As UpClass
> Static Public Function _castDown (hUpClass As UpClass) As ThisClass
> 
> The job of the interpreter would be to call these functions, in a
> possible chain, to cast automatically upside or downside every time an
> object of certain class is used in a context that requires an object of
> another class but in the same hierarchy.
> 

Hmm. I hacked the interpreter today - just to get a better idea of what is
going on in this case - and my patched gbx3 now accepts that you substitute,
e.g. VariantArray for Variant[] in the signature of VariantArray.Extract()
(of course, VariantArray Inherits Variant[]). Generally, if you override a
class' method or property, you can substitute any class farther up the
inheritance hierarchy with the overriding class. Here is a slightly related
post by Benoit about signature checks[0] but I don't know if the reasoning
applies to inherited classes, too... but continue reading:

After I got the signature accepted, there were type conversion problems when
I tried to convert the return value of Super.Extract(), which is Variant[],
as a VariantArray. I hacked that away too in the two possible ways:

(1) When VariantArray = Variant[], leave the value be a Variant[] behind the
    scenes. This imposed the problem that a subsequent call to Extract()
    would use Variant[]'s version and thus make the object useless (e.g. no
    Update events anymore).

(2) When VariantArray = Variant[], I told the type system that the Variant[]
    is legally a VariantArray and that made the interpreter segfault deep
    inside its gears (which was expected).

So there must be some serious technical reason against that. But only Benoit
can tell us the truth.

We could circumvent that crash when we simply disallowed that conversion and
had a method that would create a VariantArray from a Variant[], by copying
elements.

There is a _convert interface available for native classes (those written in
C/C++) to convert an object into another one of a different class. That this
is unavailable to Gambas programmers has obvious technical reasons. But the
one _convert() implementation I looked at (in gb.clipper), did the same: it
created a new object of the destination type and copied the relevant parts
of itself into that new object.

Regards,
Tobi

[0] http://sourceforge.net/p/gambas/mailman/message/30783547/

PS: I know that this post doesn't really show any results but it took me
    some hours to get all the stuff done to write it so I feel that I
    deserved to send it :-)

-- 
"There's an old saying: Don't change anything... ever!" -- Mr. Monk




More information about the User mailing list