Vi riporto questa discussione apparsa nella M.L. ufficiale:
" Hello Gambas users and developers!
I've been studying Gambas for almost a week and a half and I'm very
impressed with the simplicity and elegance of Gambas' object oriented
Basic language implementation. Congratulations to all developers,
specially Benoît Minisini. What a superb software development
environment you've shared with us! I hope I can join you soon to work
on its development.
In the mean time, I'd like to kindly ask for some clarifications
regarding the treatment of classes by the interpreter.
Let 'MMain' be the main module of a Gambas program and the
meta-syntactic variables 'CLASS-CLASS' and 'OBJECT-CLASS' be the
expressions 'MMain' and 'Class.Load("MMain")' respectivelly. Consider
the evaluation of the following expressions inside the 'Main' method of
'MMain' module:
TypeOf(CLASS-CLASS) ==> gb.Class
TypeOf(OBJECT-CLASS) ==> gb.Object
As you can see the CLASS-CLASS expression yields a class, while
OBJECT-CLASS expression yields an object. One might wonder what's the
class of the latter:
OBJECT-CLASS Is Class ==> True
That's expected as we may presume OBJECT-CLASS evaluates to an object,
of the class 'Class', which describes the class 'MMain', which in its
turn is the result of the evaluation of CLASS-CLASS. Surprisingly
enough, when one applies the same expression to CLASS-CLASS they
obtain:
CLASS-CLASS Is Class ==> True
The only possible explanation is that CLASS-CLASS is simultaneously a
class and an object. However, it doesn't behave as an usual instance of
the class 'Class'. For instance, it is impossible to access the public
methods and properties defined within the class 'Class' using some
expression like 'CLASS-CLASS.SYMBOL' where the meta-syntactic variable
'SYMBOL' is a public symbol of the class 'Class'. Therefore, the
assertion that CLASS-CLASS evaluates to some object which is an
instance of the class 'Class' is somewhat meaningless underneath the
usual concept of class/instance of object oriented programming.
My first question is: why does Gambas behave this way? What's the
reasoning backing up the exception to the general rule that the
evaluation of 'CLASS-CLASS', while an instance of the class 'Class',
represents? Would not it be simpler and more intuitive (hopefully
without loss of technical merits) to take CLASS-CLASS as just a "pure"
class?
I came to this issue while writing a method for validation of function
signatures in a component I'm working on. It works well with methods
residing in dynamic classes, since given an object 'OBJECT' which is an
instance of a dynamic class 'CLASS' which implements the method
'METHOD', one can easily obtain the method's signature with the
expression 'Object.Class(OBJECT)["METHOD"].Signature'. However, for
static classes I couldn't find a way to obtain the signature directly
from the class object given that
'Object.Class(CLASS)["METHOD"].Signature' wouldn't work since
'Object.Class(CLASS)' evaluates to the class 'Class' and not 'CLASS' as
would be desired, and we couldn't use it directly as in the expression
'CLASS["METHOD"].Signature' as one would naturally expect after
pondering about the fact, pointed out above, that 'CLASS Is Class'
yields 'True'.
The only way I have succeeded to obtain the signature is using the name
'NAME' of the static class 'CLASS' within the expression
'Class.Load("NAME")["METHOD"].Signature'. That is unfortunate because
I'm compelled to discriminate between static and dynamic classes, not
to mention I need to find a way to obtain the name of a static class
from itself. I thought there could be a more elegant solution. Is
there? The ideal solution would be to provide a general way to get the
"true" object of the class 'Class' which describes the class 'CLASS',
since the fact that 'CLASS' is a "false" (and bastard) object of the
class 'Class', and therefore doesn't describe its own properties while
a Class --- but the properties of its objects --- is immaterial to any
practical application I could think of. Summarizing: currently it
seems only to be possible to obtain an object of the class 'Class'
which describes the class 'CLASS' if you have an object which is an
instance of it; therefore it only works for dynamic classes, and you
have the burden of instantiation. Maybe I haven't looked into the
right place. Could you, please, help me?
Related to this issue is the problem of having a variable callback
function as a property of some object from a given class. What do you
think is the best way to setup a callback function for a method? Just
to make it less abstract: I'm writing a component for plotting
arbitrary numeric functions. The class 'Plot' implements all the plot
logic, but it must callback a function, defined by the parent which
instantiates it, to calculate the plot points. What's the best way to
implement this behavior? I've tried defining an event for 'Plot' class
so each time the 'Plot' object would need to (re)calculate the points,
let's say for a change in the intended interval of the function's
domain, the event would be raised, so the parent would have to be
observing the 'Plot' object to intercept the raised event and then do
the calculation. The problem is that by design the event handlers
don't return values to the offending object, so the event handler at
hand would have to make sure of returning it in some other
pre-established manner, like storing the computed point in 'Last.Y', and
there would be no check from the interpreter about the implementation
following the function's signature and returning a 'Float' value, for
example. So, I decided instead to store the object and method's name
that implements the mathematical function into the Plot object, so it
could call it for the computation of points and invariably receive a
return value. But for that to work correctly I needed to check the
function's signature. That's why I ultimately came to the issues
presented above. One initial hope I had was that 'Function' were a
native type of Gambas, as suggested by the expression evaluation
'TypeOf(FUNCTION) ==> gb.Function', where FUNCTION is the
meta-syntactic variable for a function symbol in the current scope.
Unfortunately, that turned out to not be true. Is there any reason to
not make functions first-class citizens? That would solve my entire
problem from the root, albeit the considerations given above are
somewhat unrelated and should be considered anyway.
Do you suggest a fourth way of implementing the callback function? Is
there a standard or ad-hoc way I'm missing?
Thank you in advance.
Bruno "
" If I have understood correctly you are referring to MMain which is module,
not normal class.
And in modules everything is static automatically.
I will look more closely later.
Jussi "
" I think you mean they aren't dynamic classes. Modules are static
classes by definition, aren't they?
Anyway, the reasoning until the paragraph you quoted above is
independent of that attribute of classes; I mean, regardless of
'CLASS-CLASS' being static or dynamic every expression described until
that paragraph works the same way. In the text I wrote, the differences
between dynamic and static classes only show up in the process of
obtaining a proper object of the class 'Class' which describes the
given class 'CLASS-CLASS', what is perfectly possible for dynamic
classes, but I fail to see how to accomplish the same with static
classes without the knowledge of its name at compilation time.
Bruno "