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