summaryrefslogtreecommitdiffstats
path: root/doc/src/templates.qdoc
blob: 8cfb8517a954e6202590d57884abe6a57859b47c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \page templates.html
    \title Why Doesn't Qt Use Templates for Signals and Slots?
    \ingroup architecture
    \brief The reasoning behind Qt's implementation of signals and slots.

    Templates are a builtin mechanism in C++ that allows the compiler to
    generate code on the fly, depending on the type of the arguments
    passed. As such, templates are highly interesting to framework
    creators, and we do use advanced templates in many places
    in Qt. However, there are limitations: There are things that you can
    easily express with templates, and there are things that are
    impossible to express with templates. A generic vector container class
    is easily expressible, even with partial specialisation for pointer
    types, while a function that sets up a graphical user interface based
    on a XML description given as a string is not expressible as
    template. And then there is gray area in between. Things that you can
    hack with templates at the cost of code size, readability,
    portability, usability, extensability, robustness and ultimately
    design beauty. Both templates and the C preprocessor can be stretched
    to do incredibility smart and mind boggling things. But just because
    those things can be done, does not necessarily mean doing them is the
    right design choice.

    There is an important practical challenge we have to mention: due to
    the inadequacies of various compilers it is still not possible to
    fully exploit the template mechanism in cross-platform
    applications. Code unfortunately is not meant to be published in
    books, but compiled with real-world compilers on real-world operating
    system. Even today, many widely used C++ compilers have problems with
    advanced templates. For example, you cannot safely rely on partial
    template specialisation, which is essential for some non-trivial
    problem domains. Some compilers also have limitations with regards to
    template member functions, which make it hard to combine generic
    programming with object orientated programming. However, we do not
    perceive these problems as a serious limitation in our work. Even if
    all our users had access to a fully standards compliant modern C++
    compiler with excellent template support, we would not abandon the
    string-based approach used by our meta object compiler for a template
    based signals and slots system. Here are five reasons why:

    \section1 Syntax matters

    Syntax isn't just sugar: the syntax we use to express our algorithms can
    significantly affect the readability and maintainability of our code.
    The syntax used for Qt's signals and slots has proved very successful in
    practice. The syntax is intuitive, simple to use and easy to read.
    People learning Qt find the syntax helps them understand and utilize the
    signals and slots concept -- despite its highly abstract and generic
    nature. Furthermore, declaring signals in class definitions ensures that
    the signals are protected in the sense of protected C++ member
    functions. This helps programmers get their design right from the very
    beginning, without even having to think about design patterns.

    \section1 Code Generators are Good

    Qt's \c{moc} (Meta Object Compiler) provides a clean way to go
    beyond the compiled language's facilities. It does so by generating
    additional C++ code which can be compiled by any standard C++ compiler.
    The \c{moc} reads C++ source files. If it finds one or more class
    declarations that contain the Q_OBJECT macro, it produces another C++
    source file which contains the meta object code for those classes. The
    C++ source file generated by the \c{moc} must be compiled and
    linked with the implementation of the class (or it can be
    \c{#included} into the class's source file). Typically \c{moc}
    is not called manually, but automatically by the build system, so it
    requires no additional effort by the programmer.

    The \c{moc} is not the only code generator Qt is using. Another
    prominent example is the \c{uic} (User Interface Compiler). It
    takes a user interface description in XML and creates C++ code that
    sets up the form. Outside Qt, code generators are common as well. Take
    for example \c{rpc} and \c{idl}, that enable programs or
    objects to communicate over process or machine boundaries. Or the vast
    variety of scanner and parser generators, with \c{lex} and
    \c{yacc} being the most well-known ones. They take a grammar
    specification as input and generate code that implements a state
    machine. The alternatives to code generators are hacked compilers,
    proprietary languages or graphical programming tools with one-way
    dialogs or wizards that generate obscure code during design time
    rather than compile time. Rather than locking our customers into a
    proprietary C++ compiler or into a particular Integrated Development
    Environment, we enable them to use whatever tools they prefer. Instead
    of forcing programmers to add generated code into source repositories,
    we encourage them to add our tools to their build system: cleaner,
    safer and more in the spirit of UNIX.


    \section1 GUIs are Dynamic

    C++ is a standarized, powerful and elaborate general-purpose language.
    It's the only language that is exploited on such a wide range of
    software projects, spanning every kind of application from entire
    operating systems, database servers and high end graphics
    applications to common desktop applications. One of the keys to C++'s
    success is its scalable language design that focuses on maximum
    performance and minimal memory consumption whilst still maintaining
    ANSI C compatibility.

    For all these advantages, there are some downsides. For C++, the static
    object model is a clear disadvantage over the dynamic messaging approach
    of Objective C when it comes to component-based graphical user interface
    programming. What's good for a high end database server or an operating
    system isn't necessarily the right design choice for a GUI frontend.
    With \c{moc}, we have turned this disadvantage into an advantage,
    and added the flexibility required to meet the challenge of safe and
    efficient graphical user interface programming.

    Our approach goes far beyond anything you can do with templates. For
    example, we can have object properties. And we can have overloaded
    signals and slots, which feels natural when programming in a language
    where overloads are a key concept. Our signals add zero bytes to the
    size of a class instance, which means we can add new signals without
    breaking binary compatibility. Because we do not rely on excessive
    inlining as done with templates, we can keep the code size smaller.
    Adding new connections just expands to a simple function call rather
    than a complex template function. 

    Another benefit is that we can explore an object's signals and slots at
    runtime. We can establish connections using type-safe call-by-name,
    without having to know the exact types of the objects we are connecting.
    This is impossible with a template based solution. This kind of runtime
    introspection opens up new possibilities, for example GUIs that are
    generated and connected from Qt Designer's XML UI files.

    \section1 Calling Performance is Not Everything

    Qt's signals and slots implementation is not as fast as a
    template-based solution. While emitting a signal is approximately the
    cost of four ordinary function calls with common template
    implementations, Qt requires effort comparable to about ten function
    calls. This is not surprising since the Qt mechanism includes a
    generic marshaller, introspection, queued calls between different
    threads, and ultimately scriptability. It does not rely on excessive
    inlining and code expansion and it provides unmatched runtime
    safety. Qt's iterators are safe while those of faster template-based
    systems are not. Even during the process of emitting a signal to
    several receivers, those receivers can be deleted safely without your
    program crashing. Without this safety, your application would
    eventually crash with a difficult to debug free'd memory read or write
    error.

    Nonetheless, couldn't a template-based solution improve the performance
    of an application using signals and slots? While it is true that Qt adds
    a small overhead to the cost of calling a slot through a signal, the
    cost of the call is only a small proportion of the entire cost of a
    slot. Benchmarking against Qt's signals and slots system is typically
    done with empty slots. As soon as you do anything useful in your slots,
    for example a few simple string operations, the calling overhead becomes
    negligible. Qt's system is so optimized that anything that requires
    operator new or delete (for example, string operations or
    inserting/removing something from a template container) is significantly
    more expensive than emitting a signal.

    Aside: If you have a signals and slots connection in a tight inner loop
    of a performance critical task and you identify this connection as the
    bottleneck, think about using the standard listener-interface pattern
    rather than signals and slots. In cases where this occurs, you probably
    only require a 1:1 connection anyway. For example, if you have an object
    that downloads data from the network, it's a perfectly sensible design
    to use a signal to indicate that the requested data arrived. But if you
    need to send out every single byte one by one to a consumer, use a
    listener interface rather than signals and slots.

    \section1 No Limits

    Because we had the \c{moc} for signals and slots, we could add
    other useful things to it that could not be done with templates.
    Among these are scoped translations via a generated \c{tr()}
    function, and an advanced property system with introspection and
    extended runtime type information. The property system alone is a
    great advantage: a powerful and generic user interface design tool
    like Qt Designer would be a lot harder to write - if not impossible -
    without a powerful and introspective property system. But it does not
    end here. We also provide a dynamic qobject_cast<T>() mechanism
    that does not rely on the system's RTTI and thus does not share its
    limitations. We use it to safely query interfaces from dynamically
    loaded components. Another application domain are dynamic meta
    objects. We can e.g. take ActiveX components and at runtime create a
    meta object around it. Or we can export Qt components as ActiveX
    components by exporting its meta object. You cannot do either of these
    things with templates.

    C++ with the \c{moc} essentially gives us the flexibility of
    Objective-C or of a Java Runtime Environment, while maintaining C++'s
    unique performance and scalability advantages. It is what makes Qt the
    flexible and comfortable tool we have today.

*/