[Gambas-user] Advising methods of non-fixed argument tuple in a parent class
Tobias Boege
taboege at ...626...
Tue Apr 15 12:55:51 CEST 2014
On Mon, 14 Apr 2014, Bruno F??lix Rezende Ribeiro wrote:
> Hello all!
>
> Suppose we want an array of variants which has the nice property of
> raising an event after any modification, like addition or removal of
> elements, has occurred to itself. Since the class 'Variant[]' does not
> have this specific capability but, on the order hand, has every other
> desired array handling functionality we need, we'll make good use of
> the OOP philosophy of re-usability and extend it to add our desired
> functionality.
>
> Our extended class will be called 'VariantArray' and will have an
> event called "Update" that will be raised after any modification
> procedure has taken place. Therefore, in its header we so declare:
>
> Inherits Variant[]
> Event Update()
>
> We now need to advise[1] the parent's methods intended for modification
> of the array structure. The idea is rather simple: we supplement a
> parent's method definition by simply raising the 'Update' event
> after its completion. Let's use the special method '_put' as our
> example case. This method allows instances of our class to be used
> as arrays in assignments.
>
> In a hypothetical N-dimensional array we'd have the following signature:
>
> Public Sub _put(vVariant As Variant, iIndex1 As Integer, ...,
> iIndexN As Integer)
>
> Where '...' is a meta-syntactical symbol which represents the full list
> of indexes parameters varying from 2 to N-1. Thus the
> override function would be:
>
> Public Sub _put(vVariant As Variant, iIndex1 As Integer, ...,
> iIndexN As Integer)
>
> Super._put(vVariant, iIndex1, ..., iIndexN)
> Raise Update()
>
> End
>
> For an array of non-fixed size we'd have the following signature:
>
> Public Sub _put(vVariant As Variant, iIndex1 As Integer, ...)
>
> Where the syntactical symbol '...' means the method can take extra
> arguments. As the result of the definition of an arbitrary argument
> tuple there is no way the previous syntax for calling the parent's
> method definition could possibly work, i.e., in the expression
>
> Super._put(vVariant, iIndex1, ...)
>
> there is no string of syntactical symbols one could replace the
> meta-syntactical symbol '...' in order to make the parent's '_put'
> method receive the same argument tuple of the child '_put' method.
>
> The only hope to solve this problem is to use the static class 'Param'
> to access the extra arguments in the form of an array. However, we
> can't use an ordinary function call to accomplish what we want, because
> it won't accept an array as a meta-argument. Fortunately that's what
> the method 'Call' of the 'Object' class provides us. Therefore, being
> 'PARENT' the meta-syntactical variable whose hypothetical syntactic
> expression points to the parent's method implementations, we'd use:
>
> Object.Call(PARENT, "_put", [vVariant, iIndex1].Insert(Param.All))
>
> Even so, there is no expression one could fit in 'PARENT' that would
> make the call work as intended. In the previous case of an arbitrary
> but defined number of arguments we used the 'Super' keyword to
> reference the parent's method implementation. This worked there
> because it was a direct and imediate use, and would not work here in
> place of 'PARENT'.
>
> So we are stuck, because to reference the parent's method
> implementation we need to use a syntax which doesn't allow the use of
> a non-fixed tuple of arguments, and in order to use a non-fixed tuple of
> arguments we have to give up our ability of referencing the parent's
> method implementation. The conclusion is quite clear: it can't be done.
>
> My questions are: is there any error with the reasoning given above? If
> not, is there a workaround? If not, how could we improve Gambas to
> solve this problem? Irrespective to all of this, do you suggest another
> approach to accomplish the initial objective of obtaining an array
> which raises events when modified? What about the general idea of
> advising methods of an inherited class? In general, how can we make it
> work?
>
>
> Thank you for your attention.
> I look forward to your answer.
>
>
> Footnotes:
>
> [1] I've borrowed the term "advice" from the GNU Emacs
> terminology for a very similar concept. Here is what its manual says
> about it:
>
> The "advice" feature lets you add to the existing definition
> of a function, by "advising the function". This is a cleaner
> method for a library to customize functions defined within
> Emacs--cleaner than redefining the whole function."
>
If I was to sum up your post: you want to call a method of Super with a
variable argument list?
AFAIK, you are right that we cannot call Super._put() directly when we want
to pass a variable number of arguments. For that, we need to manipulate the
Gambas stack to push that stuff and then call the method. That's precisely
when Object.Call() would come into play and AFAIK, you are right, too, in
that we cannot use Super there as it cannot be used alone. And there is no
other way of accessing our inherited class. That looks like a limitation.
However, multi-dimensional arrays are limited to eight dimensions in Gambas,
so there is no practical problem at present that would you keep you from
Select-Case'ing Param.Count and doing Super[cased-arg-list-here] = vValue.
But I believe in the existence of problems of bigger importance than
practical problems, like ideational ones [ hope that's the right English
word... ] where the above solution fails miserably.
In the Tobias-Boegian school of Gambas, we distinguish between "real" multi-
dimensional arrays and "derived" multi-dimensional arrays. Real m-d arrays
are those you were about to use, the ones you declare with Variant[iDim1,
iDim2, ..., iDimN] where N <= 8. These have at least three drawbacks:
(1) their number of dimensions is limited by 8;
(2) the size of each dimension is static; and
(3) they can only shape like matrices.
Derived m-d arrays are array classes built by the interpreter out of other
classes. If you have a class x, then x[] denotes an array type containing
elements of type x. Moreover, x[] is again a class. So if you repeat that
process, you obtain x[][] which is an array class that can hold x[] objects.
Let's look at the three above points. It turns out that derived m-d arrays
are superior:
(1) no limit;
(2) sizes of dimensions are fully dynamic; and
(3) we are not limited to matrix-shape.
Maybe now it becomes clear what I meant with matrix-shaped: if you have real
m-d arrays, any dimension must have the same size at every point, e.g. if
you have a m-d array of three dimensions, it will always look like a cuboid.
Whereas 3d derived m-d arrays are arrays of arrays of arrays and every two
arrays in that system may have different sizes. [ I first posted that
explanation here[0]. ]
If you are willing to use derived arrays (there seems no reason against),
you don't have that problem of variable argument lists, as there is no
syntactic multi-dimensional-ity, you just happen to access 1d arrays whose
elements are again arrays.
And finally let me tell you something about extending classes: it gets
especially cool when you call your extending class like the extended class.
Above, you would not call your class VariantArray but Variant[]. [ At
present, you have to create .src/Variant[].class outside of the IDE in your
project because the IDE forbids use of brackets in class names. However, the
interpreter doesn't seem to have any problems with that. ]
That way, you are overriding the Variant[] class in the interpreter's global
symbol table, using inheritance, i.e. you extend it. You can add features to
Variant[] which are immediately available to all users of the Variant[]
class without having to change any code. That's explained in the docs as
well[1].
Regards,
Tobi
[0] http://gambas-club.de/viewtopic.php?f=3&t=4688#p9975
[1] http://gambaswiki.org/wiki/doc/object-model
--
"There's an old saying: Don't change anything... ever!" -- Mr. Monk
More information about the User
mailing list