1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation (qt-info@nokia.com)
|
---|
6 | **
|
---|
7 | ** This file is part of the documentation of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:FDL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in a
|
---|
14 | ** written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Free Documentation License
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Free
|
---|
18 | ** Documentation License version 1.3 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file included in the packaging of this
|
---|
20 | ** file.
|
---|
21 | **
|
---|
22 | ** If you have questions regarding the use of this file, please contact
|
---|
23 | ** Nokia at qt-info@nokia.com.
|
---|
24 | ** $QT_END_LICENSE$
|
---|
25 | **
|
---|
26 | ****************************************************************************/
|
---|
27 |
|
---|
28 | /*!
|
---|
29 | \title Moving from QSA to Qt Script
|
---|
30 | \page porting-qsa.html
|
---|
31 | \ingroup porting
|
---|
32 |
|
---|
33 | The purpose of this document is to map the differences between Qt
|
---|
34 | Script for Applications (QSA) and Qt Script, the ECMAScript compatible
|
---|
35 | engine supplied with Qt 4.3. This document is not supposed to be a
|
---|
36 | complete function by function porting guide, but will cover the most
|
---|
37 | obvious aspects.
|
---|
38 |
|
---|
39 | First of all it is important to realize that Qt Script is only an
|
---|
40 | interpreter, it does not provide an editor, completion or script project
|
---|
41 | management, like QSA does. Qt Script however does provides almost full
|
---|
42 | compliance with the ECMAScript standard and performs significantly
|
---|
43 | better than the script engine provided by QSA.
|
---|
44 |
|
---|
45 | \tableofcontents
|
---|
46 |
|
---|
47 | \section1 The Scripting Language
|
---|
48 |
|
---|
49 | The scripting language used in QSA, from here on referred to as QSA,
|
---|
50 | was derived from ECMAScript 3.0 and 4.0 and is a hybrid of these
|
---|
51 | standards. Most of the run-time logic, such as classes and scoping
|
---|
52 | rules, is based on the ECMAScript 4.0 proposal, while the library
|
---|
53 | implementation is based on the ECMAScript 3.0 standard.
|
---|
54 | Qt Script on the other hand is solely based on the ECMAScript 3.0
|
---|
55 | standard. Though the languages look identical at first glance,
|
---|
56 | there are a few differences that we'll cover in the sections below.
|
---|
57 |
|
---|
58 |
|
---|
59 | \section2 Classes vs. Objects and Properties
|
---|
60 |
|
---|
61 | QSA implements classes and inheritance much in a familiar way to users
|
---|
62 | of other object oriented languages, like C++ and Java. However, the
|
---|
63 | ECMAScript 3.0 standard defines that everything is an object, and objects
|
---|
64 | can have named properties. For instance to create an point object with
|
---|
65 | the properties x and y one would write the following Qt Script code:
|
---|
66 |
|
---|
67 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 0
|
---|
68 |
|
---|
69 | The object \c point in this case is constructed as a plain object and
|
---|
70 | we assign two properties, \c x and \c y, to it with the values 12 and
|
---|
71 | 35. The \c point object is assigned to the "Global Object" as the
|
---|
72 | named property \c{point}. The global object can be considered the
|
---|
73 | global namespace of the script engine. Similarly, global functions are
|
---|
74 | named properties of the global object; for example:
|
---|
75 |
|
---|
76 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 1
|
---|
77 |
|
---|
78 | An equivalent construction that illustrates that the function is a
|
---|
79 | property of the global object is the following assignment:
|
---|
80 |
|
---|
81 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 2
|
---|
82 |
|
---|
83 | Since functions are objects, they can be assigned to objects as
|
---|
84 | properties, becoming member functions:
|
---|
85 |
|
---|
86 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 3
|
---|
87 |
|
---|
88 | In the code above, we see the first subtle difference between
|
---|
89 | QSA and Qt Script. In QSA one would write the point class like this:
|
---|
90 |
|
---|
91 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 4
|
---|
92 |
|
---|
93 | where in the \c manhattanLength() function we access \c x and \c y
|
---|
94 | directly because, when the function is called, the \c this object is
|
---|
95 | implicitly part of the current scope, as in C++. In Qt Script,
|
---|
96 | however, this is not the case, and we need to explicitly access
|
---|
97 | the \c x and \c y values via \c{this}.
|
---|
98 |
|
---|
99 | All the code above runs with QSA except the assignment of a function
|
---|
100 | to \c{point.manhattanLength}, which we repeat here for clarity:
|
---|
101 |
|
---|
102 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 5
|
---|
103 |
|
---|
104 | This is because, in QSA, the value of \c this is decided based on
|
---|
105 | the location of the declaration of the function it is used in. In the
|
---|
106 | code above, the function is assigned to an object, but it is declared
|
---|
107 | in the global scope, hence there will be no valid \c this value.
|
---|
108 | In Qt Script, the value of \c this is decided at run-time,
|
---|
109 | hence you could have assigned the \c manhattanLength() function to any
|
---|
110 | object that had \c x and \c y values.
|
---|
111 |
|
---|
112 |
|
---|
113 | \section2 Constructors
|
---|
114 |
|
---|
115 | In the code above, we use a rather awkward method for constructing
|
---|
116 | the objects, by first instantiating them, then manually
|
---|
117 | assigning properties to them. In QSA, the proper way to solve this
|
---|
118 | is to implement a constructor in the class:
|
---|
119 |
|
---|
120 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 6
|
---|
121 |
|
---|
122 | The equivalent in Qt Script is to create a constructor function:
|
---|
123 |
|
---|
124 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 7
|
---|
125 |
|
---|
126 | As we can see, the constructor is just a normal function. What is
|
---|
127 | special with is how we call it, namely prefixed with the \c new
|
---|
128 | keyword. This will create a new object and call the \c Car()
|
---|
129 | function with the newly created object as the \c this pointer.
|
---|
130 | So, in a sense, it is equivalent to:
|
---|
131 |
|
---|
132 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 8
|
---|
133 |
|
---|
134 | This is similar to the manhattenLength() example above. Again, the
|
---|
135 | main difference between QSA and Qt Script is that one has to
|
---|
136 | explicitly use the keyword \c this to access the members and that
|
---|
137 | instead of declaring the variable, \c regNumber, we just extend the
|
---|
138 | \c this object with the property.
|
---|
139 |
|
---|
140 |
|
---|
141 | \section2 Member Functions and Prototypes
|
---|
142 |
|
---|
143 | As we saw above, one way of creating member functions of a Qt Script
|
---|
144 | object is to assign the member function to the object as a property
|
---|
145 | and use the \c this object inside the functions. So, if we add a
|
---|
146 | \c toString function to the \c Car class
|
---|
147 |
|
---|
148 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 9
|
---|
149 |
|
---|
150 | one could write this in Qt Script as:
|
---|
151 |
|
---|
152 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 10
|
---|
153 |
|
---|
154 | In QSA, the member functions were part of the class declaration,
|
---|
155 | and were therefore shared between all instances of a given class.
|
---|
156 | In Qt Script, each instance has a instance member for each function.
|
---|
157 | This means that more memory is used when multiple instances are used.
|
---|
158 | Qt Script uses prototypes to remedy this.
|
---|
159 |
|
---|
160 | The basic prototype-based inheritance mechanism works as follows.
|
---|
161 | Each Qt Script object has an internal link to another object, its
|
---|
162 | prototype. When a property is looked up in an object, and the object
|
---|
163 | itself does not have the property, the interpreter searches for the
|
---|
164 | property in the prototype object instead; if the prototype has the
|
---|
165 | property then that property is returned. If the prototype object does
|
---|
166 | not have the property, the interpreter searches for the property in
|
---|
167 | the prototype of the prototype object, and so on.
|
---|
168 |
|
---|
169 | This chain of objects constitutes a prototype chain. The chain of
|
---|
170 | prototype objects is followed until the property is found or the end
|
---|
171 | of the chain is reached.
|
---|
172 |
|
---|
173 | To make the \c toString() function part of the prototype, we write
|
---|
174 | code like this:
|
---|
175 |
|
---|
176 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 11
|
---|
177 |
|
---|
178 | Here, we made the \c toString() function part of the prototype so
|
---|
179 | that, when we call \c{car.toString()} it will be resolved via the
|
---|
180 | internal prototype object of the car object. Note, however, that the
|
---|
181 | \c this object is still the original object that the function was
|
---|
182 | called on, namely \c{car}.
|
---|
183 |
|
---|
184 |
|
---|
185 | \section2 Inheritance
|
---|
186 |
|
---|
187 | Now that we've seen how to use prototypes to create a "class" members
|
---|
188 | in Qt Script, let's see how we can use prototypes to create
|
---|
189 | polymorphism. In QSA you would write
|
---|
190 |
|
---|
191 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 12
|
---|
192 |
|
---|
193 | With Qt Script, we acheive the same effect by creating a prototype
|
---|
194 | chain. The default prototype of an object is a plain \c Object
|
---|
195 | without any special members, but it is possible to replace this
|
---|
196 | object with another prototype object.
|
---|
197 |
|
---|
198 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 13
|
---|
199 |
|
---|
200 | In the code above, we have a constructor, \c{GasolineCar}, which
|
---|
201 | calls the "base class" implementation of the constructor to
|
---|
202 | initialize the \c this object with the property \c{regNumber},
|
---|
203 | based on the values passed in the constructor. The interesting line
|
---|
204 | in this case is the line after the constructor where we change the
|
---|
205 | default prototype for \c GasolineCar to be an instance of type
|
---|
206 | \c{Car}. This means that all members available in a \c Car object
|
---|
207 | are now available in all \c GasolineCar objects. In the last line,
|
---|
208 | we replace the \c toString() function in the prototype with our own,
|
---|
209 | thus overriding the \c toString() for all instances of
|
---|
210 | \c{GasolineCar}.
|
---|
211 |
|
---|
212 |
|
---|
213 | \section2 Static Members
|
---|
214 |
|
---|
215 | QSA allowed users to declare static members in classes, and these
|
---|
216 | could be accessed both through instances of the class and through
|
---|
217 | the class itself. For example, the following variable is accessed
|
---|
218 | through the \c Car class:
|
---|
219 |
|
---|
220 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 14
|
---|
221 |
|
---|
222 | The equivalent in Qt Script is to assign variables that should appear
|
---|
223 | as static members as properties of the constructor function. For
|
---|
224 | example:
|
---|
225 |
|
---|
226 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 15
|
---|
227 |
|
---|
228 | Note that in QSA, static member variables were also accessible in
|
---|
229 | instances of the given class. In Qt Script, with the approach
|
---|
230 | illustrated above, the variable is a member of the constructor
|
---|
231 | object only, and thus only accessible through \c{Car.globalCount}.
|
---|
232 |
|
---|
233 |
|
---|
234 | \section1 The Built-in Functions and Library
|
---|
235 |
|
---|
236 | The built-in functions in QSA are based on those defined in the
|
---|
237 | ECMAScript 3.0 standard, the same standard used for Qt Script, but
|
---|
238 | QSA adds some extensions to this, specifically for the \c String
|
---|
239 | and \c RegExp types. QSA also lacked some functions from the
|
---|
240 | standard, most notably the \c Date type. Below we list all the
|
---|
241 | differences. All changes made to Qt Script are to increase
|
---|
242 | compliance with ECMAScript 3.0.
|
---|
243 |
|
---|
244 | \table
|
---|
245 | \header \o QSA Function \o Notes about Equivalent Qt Script Functions
|
---|
246 | \row \o eval()
|
---|
247 | \o The eval function in QSA opened a new scope for code being
|
---|
248 | executed in the eval function, so locally declared variables were not
|
---|
249 | accessible outside. In Qt Script, the eval() function shares the
|
---|
250 | current scope, making locally declared variables accessible outside
|
---|
251 | the eval() call.
|
---|
252 |
|
---|
253 | \row \o debug()
|
---|
254 | \o This function is not available in Qt Script. Use print() instead.
|
---|
255 |
|
---|
256 | \row \o connect()
|
---|
257 | \o QSA had closures, meaning that a member function
|
---|
258 | reference implicitly contained its \c this object. Qt Script does not
|
---|
259 | support this. See the Qt Script documentation for details on using the
|
---|
260 | connect function.
|
---|
261 |
|
---|
262 | \row \o String.arg()
|
---|
263 | \o This function is not available in Qt Script. Use replace() or concat() instead.
|
---|
264 |
|
---|
265 | \row \o String.argDec()
|
---|
266 | \o This function is not available in Qt Script. Use replace() or concat() instead.
|
---|
267 |
|
---|
268 | \row \o String.argInt()
|
---|
269 | \o This function is not available in Qt Script. Use replace() or concat() instead.
|
---|
270 |
|
---|
271 | \row \o String.argStr()
|
---|
272 | \o This function is not available in Qt Script. Use replace() or concat() instead.
|
---|
273 |
|
---|
274 | \row \o String.endsWith()
|
---|
275 | \o This function is not available in Qt Script. Use lastIndexOf() instead.
|
---|
276 |
|
---|
277 | \row \o String.find()
|
---|
278 | \o This function is not available in Qt Script. Use indexOf() instead.
|
---|
279 |
|
---|
280 | \row \o String.findRev()
|
---|
281 | \o This function is not available in Qt Script. Use lastIndexOf() and length instead.
|
---|
282 |
|
---|
283 | \row \o String.isEmpty()
|
---|
284 | \o This function is not available in Qt Script. Use length == 0 instead.
|
---|
285 |
|
---|
286 | \row \o String.left()
|
---|
287 | \o This function is not available in Qt Script. Use substring() instead.
|
---|
288 |
|
---|
289 | \row \o String.lower()
|
---|
290 | \o This function is not available in Qt Script. Use toLowerCase() instead.
|
---|
291 |
|
---|
292 | \row \o String.mid()
|
---|
293 | \o This function is not available in Qt Script. Use substring() instead.
|
---|
294 |
|
---|
295 | \row \o String.right()
|
---|
296 | \o This function is not available in Qt Script. Use substring() instead.
|
---|
297 |
|
---|
298 | \row \o String.searchRev()
|
---|
299 | \o This function is not available in Qt Script. Use search() / match() instead.
|
---|
300 |
|
---|
301 | \row \o String.startsWith()
|
---|
302 | \o This function is not available in Qt Script. Use indexOf() == 0 instead.
|
---|
303 |
|
---|
304 | \row \o String.upper()
|
---|
305 | \o This function is not available in Qt Script. Use toUpperCase() instead.
|
---|
306 |
|
---|
307 | \row \o RegExp.valid
|
---|
308 | \o This property is not available in Qt Script because it is not
|
---|
309 | required; a \c SyntaxError exception is thrown for bad \c RegExp objects.
|
---|
310 |
|
---|
311 | \row \o RegExp.empty
|
---|
312 | \o This property is not available in Qt Script. Use \c{toString().length == 0} instead.
|
---|
313 |
|
---|
314 | \row \o RegExp.matchedLength
|
---|
315 | \o This property is not available in Qt Script. RegExp.exec() returns an
|
---|
316 | array whose size is the matched length.
|
---|
317 |
|
---|
318 | \row \o RegExp.capturedTexts
|
---|
319 | \o This property is not available in Qt Script. RegExp.exec() returns an
|
---|
320 | array of captured texts.
|
---|
321 |
|
---|
322 | \row \o RegExp.search()
|
---|
323 | \o This function is not available in Qt Script. Use RegExp.exec() instead.
|
---|
324 |
|
---|
325 | \row \o RegExp.searchRev()
|
---|
326 | \o This function is not available in Qt Script. Use RegExp.exec() or
|
---|
327 | String.search()/match() instead.
|
---|
328 |
|
---|
329 | \row \o RegExp.exactMatch()
|
---|
330 | \o This function is not available in Qt Script. Use RegExp.exec() instead.
|
---|
331 |
|
---|
332 | \row \o RegExp.pos()
|
---|
333 | \o This function is not available in Qt Script. Use String.match() instead.
|
---|
334 |
|
---|
335 | \row \o RegExp.cap()
|
---|
336 | \o This function is not available in Qt Script. RegExp.exec() returns an
|
---|
337 | array of captured texts.
|
---|
338 | \endtable
|
---|
339 |
|
---|
340 | QSA also defined some internal Qt API which is not present in Qt
|
---|
341 | Script. The types provided by QSA which are not provided by Qt Script are:
|
---|
342 |
|
---|
343 | \list
|
---|
344 | \o Rect
|
---|
345 | \o Point
|
---|
346 | \o Size
|
---|
347 | \o Color
|
---|
348 | \o Palette
|
---|
349 | \o ColorGroup
|
---|
350 | \o Font
|
---|
351 | \o Pixmap
|
---|
352 | \o ByteArray
|
---|
353 | \endlist
|
---|
354 |
|
---|
355 |
|
---|
356 | \section1 The C++ API of QSA vs Qt Script
|
---|
357 |
|
---|
358 | QSA is more than just a scripting engine. It provides project
|
---|
359 | management, an editor with completion and a minimalistic IDE to edit
|
---|
360 | scriptable projects. Qt Script on the other hand is just a scripting
|
---|
361 | engine. This means that equivalents to the classes \c QSEditor,
|
---|
362 | \c QSScript, \c QSProject and \c QSWorkbench do not exist in Qt Script.
|
---|
363 | QSA also provides some extension APIs through the \c QSUtilFactory and
|
---|
364 | \c QSInputDialogFactory. There is also no equivalent to these classes
|
---|
365 | in the Qt Script API.
|
---|
366 |
|
---|
367 |
|
---|
368 | \section2 Making QObjects Accessible from Scripts
|
---|
369 |
|
---|
370 | There are two different ways of making \l{QObject}s accessible from
|
---|
371 | scripts in QSA. The first method is via the
|
---|
372 | \c QSInterpreter::addTransientObject() and \c QSProject::addObject()
|
---|
373 | functions. In this case objects are added to the global namespace of
|
---|
374 | the interpreter using their object names as the names of the
|
---|
375 | variables.
|
---|
376 |
|
---|
377 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 16
|
---|
378 |
|
---|
379 | The code above adds the button to the global namespace under the name
|
---|
380 | "button". One obvious limitation here is that there is potential for
|
---|
381 | either unnamed \l{QObject}s or objects whose names conflict. Qt Script
|
---|
382 | provides a more flexible way of adding QObjects to the scripting
|
---|
383 | environment.
|
---|
384 |
|
---|
385 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 17
|
---|
386 |
|
---|
387 | In the code above we create a QPushButton and wrap it in a script
|
---|
388 | value using the function, QScriptEngine::newQObject(). This gives us
|
---|
389 | a script value that we put into the global object using the name
|
---|
390 | "button". The concept of objects and properties discussed above is
|
---|
391 | quite visible here in the public C++ API as well. We have no
|
---|
392 | dependency on the object's name and we can also resolve name conflicts
|
---|
393 | more gracefully. Here, we operate directly on QScriptValue objects.
|
---|
394 | This is the actual object that is being passed around inside
|
---|
395 | the script engine, so we actually have low-level access to the
|
---|
396 | internal script data structures, far beyond that which is possible
|
---|
397 | in QSA. Properties, signals and slots of the QObject are accessible
|
---|
398 | to the scripter in Qt Script, just like in QSA.
|
---|
399 |
|
---|
400 | The other way to expose \l{QObject}s in QSA was to create a
|
---|
401 | \c QSObjectFactory that made it possible to instantiate QObjects from
|
---|
402 | scripts.
|
---|
403 |
|
---|
404 | Below is listed some code from the filter example in the QSA
|
---|
405 | package.
|
---|
406 |
|
---|
407 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 18
|
---|
408 |
|
---|
409 | The equivalent in Qt Script is written in much the same way as
|
---|
410 | constructors are written in scripts. We register a callback C++
|
---|
411 | function under the name "ImageSource" in the global namespace and
|
---|
412 | return the QObject from this function:
|
---|
413 |
|
---|
414 | \snippet doc/src/snippets/code/doc_src_porting-qsa.qdoc 19
|
---|
415 |
|
---|
416 | In the Qt Script case we use the same approach that we use to expose
|
---|
417 | a QObject, namely via QScriptEngine::newQObject(). This function also
|
---|
418 | has the benefit that it is possible to specify if the QObject should
|
---|
419 | expose properties and slots of its base class. It is also possible to
|
---|
420 | specify custom ownership rules.
|
---|
421 |
|
---|
422 | The reader might question why we don't add the constructor function
|
---|
423 | directly into the namespace, but create a meta-object script value for
|
---|
424 | it in addition. The plain function would certainly be good enough,
|
---|
425 | but by creating a QMetaObject based constructor we get the enums on
|
---|
426 | QPushButton for free in the QPushButton function object. Exposing
|
---|
427 | enums in QSA is rather painful in comparison.
|
---|
428 |
|
---|
429 | If we want to add more "static" data to the QPushButton type in Qt
|
---|
430 | Script, we're free to add properties, similar to how we did for
|
---|
431 | the script. It is also possible to add custom functions to a Qt Script
|
---|
432 | QPushButton instance by setting more properties on it, such as making
|
---|
433 | the \l{QPushButton::}{setText()} C++ function available. It is also
|
---|
434 | possible to acheive this by installing a custom prototype, and be
|
---|
435 | memory efficient, as discussed in the script example above.
|
---|
436 |
|
---|
437 |
|
---|
438 | \section2 Accessing Non-QObjects
|
---|
439 |
|
---|
440 | In QSA, it was possible to expose non-QObjects to QSA by wrapping them
|
---|
441 | in a QObject and using either \c QSWrapperFactory or \c QSObjectFactory
|
---|
442 | to expose them. Deciding when to use each of these classes could be
|
---|
443 | confusing, as one was used for script based construction and the other
|
---|
444 | for wrapping function parameters and return values, but in essence they
|
---|
445 | did exactly the same thing.
|
---|
446 |
|
---|
447 | In Qt Script, providing access to QObjects and non-QObjects is done in
|
---|
448 | the same way as shown above, by creating a constructor function, and
|
---|
449 | by adding properties or a custom prototype to the constructed object.
|
---|
450 |
|
---|
451 |
|
---|
452 | \section2 Data Mapping
|
---|
453 |
|
---|
454 | QSA supported a hardcoded set of type mappings which covered most
|
---|
455 | of the QVariant types, QObjects and primitives. For more complex type
|
---|
456 | signatures, such as the template-based tool classes, it had rather
|
---|
457 | limited support. Qt Script is significantly better at type mapping
|
---|
458 | and will convert lists of template types into arrays of the
|
---|
459 | appropriate types, given that all the types are declared to the
|
---|
460 | meta-type system.
|
---|
461 | */
|
---|