[Gambas-user] Interpreter's treatment of classes

Benoît Minisini gambas at ...1...
Sat Apr 12 17:38:03 CEST 2014


Le 11/04/2014 05:17, Bruno Félix Rezende Ribeiro a écrit :
> 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?

All that is because, "is a" has two meanings in Gambas.

1) An object reference A "is a" class B. It means that the class of the 
object A is the class B.

2) An expression "is a" datatype. And there are two datatypes, 
"gb.Object" and "gb.Class".

"gb.Object" is any expression that returns a non-null object reference. 
An object reference internally includes two pointers: a class pointer, 
and an object data pointer.

"gb.Class" is any expression that returns a class. It includes one 
pointer, the class pointer.

"gb.Class" exists only for internal optimization reasons. I could have 
used instead a "gb.Object", with a null object data pointer. But it 
would have been slower.

Now, as stated in the wiki, classes are really objects whose class is 
the "Class" class. But a reference to a class as an object is not the 
same thing as a reference to the class. The first one has methods that 
describe the class structure, the second one allows to call the static 
methods of the 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.
>

As there is no true function datatype at the moment, there is no true 
generic solution. (Internally, the function datatype exists, but all 
non-official things do no exist. By the way I told you nothing).

When I need doing these sorts of things, I'm only using dynamic object. 
And if I have a static class, I transform it into a auto-instanciable 
dynamic class (like Forms objects, for example).

If a class is auto-instanciable, using the class name as an object 
automatically transforms the "gb.Class" expression into a reference to 
the auto-created internal singleton object. So you exactly have the 
syntax you need.

And when I will succeed in implementing a clean global syntax, you will 
just have to transform your auto-creatable class back to a static class.

Regards,

-- 
Benoît Minisini




More information about the User mailing list