[Qtscript-bindings] Inheritance question (why call the parent constructor twice?)

Kent Hansen khansen at trolltech.com
Tue Jul 21 11:19:35 CEST 2009


Hi Thiago,

Thiago Silva wrote:
> On Fri, Jul 17, 2009 at 4:51 AM, Kent Hansen<khansen at trolltech.com> wrote:
>   
>> I don't understand the statement "editor() obviously gets called twice".
>> It gets called only once per editor and subed instance created, AFAICT.
>> The code looks perfectly fine.
>>
>>     
>
> I mean this:
>
> //--begin
> editor = function() {
>   QTextEdit.call(this)
>   print('editor was called')
> }
> editor.prototype = new QTextEdit
>
> subed = function() {
>   editor.call(this)
> }
> subed.prototype = new editor
>
> x = new QMainWindow
> ed = new subed
> x.setCentralWidget(ed)
> x.show()
> //--end
>
> evaluating the above code results in the output:
>
> "editor was called"
> "editor was called"
>
> The constructor is called when defining a prototype chain _and_ when
> creating instances of a given constructor in the chain. This is quite
> undesirable.

If "editor" is not meant to be instantiated for the purpose of
instantiation ( :-) ), but rather only to set up a prototype chain (just
one of JS's quirks; see e.g.
http://javascript.crockford.com/prototypal.html), you don't need the
QTextEdit.call() in that constructor. It can just be a plain object. The
point of the QTextEdit.call() is to work around JavaScript's inability
to let you "subclass" native objects. It changes the [[Class]] property
of the this-object so it becomes a QObject wrapper, and actually
instantiates the C++ object that the script object wraps.


>  A related problem is dealing with inheritance of
> properties: the QTextEdit.call(this) call brings all the QTextEdit
> properties directly to the "x" object, shadowing properties with the
> same name in the chain (which is odd, since QTextEdit is ancestor;
> it's properties that should be shadowed).
>   

Right, methods that are handled by QtScript's dynamic QObject binding
will override the generated bindings and classes based on them; see
http://www.qtsoftware.com/developer/task-tracker/index_html?method=entry&id=245820.
If that suggestion is implemented, the dynamic+generated bindings can
play more nicely together.

> Anyway, such code is necessary because, for every method call, the
> binding classes try to extract the c++ object from the "this" js
> object ignoring it's prototype chain.

The prototype chain is not ignored; but just because an object in the
prototype chain is of a certain type doesn't mean that the this-object
itself is of that type, from the C++ side of things. For the bindings to
make sense, we _need_ to extract a corresponding C++ object from the JS
this-object.

>  I wrote a fix for it in my
> generator, but don't know if there are any corder cases I'm unaware
> of. This fix allow me to write codes such as this:
>
> //--begin
> MyWidget = function() {
>   var bt = new QPushButton("clickme", this)
> }
> MyWidget.prototype = new QWidget()
>
> w = new MyWidget()
> w.show()
> //--end
>
> from the point of view of javascript semantics, w should pass as a
> QWidget, since that's what it's prototype object is. No need to bring
> QWidget properties to 'w' itself (which is what a QWidget.call(this)
> in the constructor would do). The above code is more javascript-ish.
>   

Yes, from JS semantics it passes as a QWidget; the issue is the C++
side. When you call w.show(), what C++ object does it call show() on? Do
you dynamically create a C++ object of the proper type the first time
someone attempts to access a QObject-inherited property in w? That would
work, I guess. It still doesn't change the point: There needs to be a
corresponding object that represents w in the C++ world; and that object
needs to know about the JS object, so that it can propagate calls from
the C++ world back to JS (this is what the generated qtscriptshell_*
classes do).

Regards,
Kent


More information about the Qtscript-bindings mailing list