doc/src/porting/porting-qsa.qdoc
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 */