Autore Topic: Metodi di tupla ad argomento non-fisso in una classe genitore  (Letto 355 volte)

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.305
  • Ne mors quidem nos iunget
    • Mostra profilo
Vi riporto questa discusone apparsa nella M.L. ufficiale:


" 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:

Codice: gambas [Seleziona]
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:

Codice: gambas [Seleziona]
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:

Codice: gambas [Seleziona]
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:
Codice: gambas [Seleziona]
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

Codice: gambas [Seleziona]
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:

Codice: gambas [Seleziona]
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."

Bruno
"


" 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: http://gambas-club.de/viewtopic.php?f=3&t=4688#p9975 . ]

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:
http://gambaswiki.org/wiki/doc/object-model

Regards,
Tobi
"
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.305
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: Metodi di tupla ad argomento non-fisso in una classe genitore
« Risposta #1 il: 16 Aprile 2014, 11:01:35 »
...continua...


" > If I was to sum up your post: you want to call a method of Super with
> a variable argument list?


Yup.  You got that perfectly right! ;-)  I wonder if using your
summarizing sentence right away from the beginning of my original
text would have had the same effect.  In affirmative case I'm
being overly verbose, but it happens that I'm not the biggest fan of
misunderstanding, so I'd rather prefer to play a little bit safer. :-P
Nevertheless, it'd be pointless if actually the extensive explanation
achieves the contrary effect: hard comprehension.  I welcome feedback
on this matter too.

>And there is no other way of accessing our
> inherited class. That looks like a limitation.


So, I guess it'd be a reasonable feature request to include at least a
way to bypass this particular limitation.  By the way, are you a Gambas
developer?


> 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.


Oh... I just forgot for a moment that hard-coded limitation of 8
dimensions.  But yeah, given that our concerns are attached to
practical situations you've suggested a perfectly acceptable solution,
unfortunately somewhat inconvenient, though; yet as convenient as it
could possibly be with the current interpreter.


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]. ]

I guess
  • is in German, and thus unfortunately I can't read it.  I

have the feeling, though I could be deadly wrong, that outside this
mailing list, there are a lot more information and discussion about
Gambas in languages other than English.  It seems that [1] supports
this claim.  It's unfortunate because fewer people can have access to
that information, and it segregates the user-base to some extent.


> 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.

I agree with you that the use of m-d derived arrays is entirely taken
care of by the interpreter and it's quite transparent to my code.
However, if I'm going to replace the class 'Variant[]' presupposing
full backward compatibility, as you've suggested below, I must make
sure my code properly handle "real" arrays as well.


>However, the interpreter doesn't seem to
> have any problems with that.


What a neat tip!  If the behavior of having classes with brackets in
their names is useful --- and even the interpreter is fine with that ---
I don't see why this wouldn't be an IDE bug.  Have you or anyone else
addressed this bug or submitted a bug report on this?

bruno
"


" > So, I guess it'd be a reasonable feature request to include at least a
> way to bypass this particular limitation.  By the way, are you a Gambas developer?


Not one of the kind that could do such a thing. I'm working on C/C++
components for Gambas (and if you write C/C++ components for Gambas, it is
inevitable to look at the interpreter's source once in a while). In the
source tree:

  $ grep -R Tobias * | egrep "\.(class|project|component)"

should show you where I've been. I develop components as there is time but
mathematics students aren't very famed around here for having much spare
time.

>It seems that [1] supports this claim.  It's unfortunate because fewer people can have access to
> that information, and it segregates the user-base to some extent.


Yeah, there is likely quite some information about Gambas only available
to a very limited community in their language - and I must admit that I
don't even attend those famous French or Spanish sites (not even
whiteislandsoftware.com).

BUT there is only one German Gambas community I know of and that's the
Gambas-Club of which I have taken care recently. Since I'm active on this
list, the link is established (it's just not broadband). Of Ru Vuott and
Willy Raets, I have noticed that they must have taken similar positions.

I suppose that this is how it works with the other forums as well. So
potentially, we can transfer most of the stuff into this list if people
ask the right questions... maybe. :-)

Too bad that you can't understand German, though. I had luck with others
in the past who could at least somewhat read German. Actually, I have
translated everything about array classes I said in that post in my last
mail but there is also a German online book[0] we're writing about Gambas
which happens to contain "original research" and "exclusive material" :-)
(may it only be up-to-date documentation of some classes).


> What a neat tip!  If the behavior of having classes with brackets in
> their names is useful --- and even the interpreter is fine with that ---
> I don't see why this wouldn't be an IDE bug.  Have you or anyone else
> addressed this bug or submitted a bug report on this?


It was discussed already in this thread:
http://sourceforge.net/p/gambas/mailman/message/29417207/

> Poor 'Array' class... it doesn't have any events --- let's give it some useful ones. ;-)

That would mean overhead which is unnecessary - I dare to say - _most_ of
the time. I myself never needed a data container which would tell me when
it changed. That is also a decision I have made for gb.data: classes in
there are data containers. They don't communicate with me (raise events),
they only contain.

And raising an event in code means to execute some functions, no matter if
that object is actually able to generate events. It is not, e.g. when it
has no event name which is the case for all current code. Since changing
data in an array is surely one of its most used functions, it would be cool
to see a benchmark with and without that event. But I bet the benchmark
with event wouldn't look too nice...

Regards,
Tobi
"


" I just want to say that if you have problem with Gambas inheritance and
"SUPER" limitations, you can replace inheritance by "composition".

I mean : instead of inheriting "Variant[]" or reimplementing it, you can
create your own "MyVariantArray" class that embeds a Variant array as a
private dynamic variable. Then you will be able to do almost everything
you need.

Another point: It's not a good idea to reimplement native array classes.
These classes must be as fast as possible, they are used everywhere. I
don't think that you need an "Update" event for every array in your
application, do you?

Regards,

--
Benoît Minisini
"
« Ultima modifica: 22 Aprile 2014, 12:54:59 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.305
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: Metodi di tupla ad argomento non-fisso in una classe genitore
« Risposta #2 il: 23 Aprile 2014, 16:31:51 »
...continua...


" > Then you will be able to do
> almost everything you need.


Indeed, "composition" is the best option given the current situation.
Wise advice.  Correct if I'm wrong, but I think that is best exploited
when using '_unknown' and '_property' special methods to
transparently deliver any method or property request directly to the
private dynamic array.  This way one don't have to wrap every possible
array method or property and the class can be made agnostic of array
type.

> I don't think that you need an "Update" event for every
> array in your application, do you?


No, I don't.  It's a very specific use case.

Bruno
"
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »