|
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 \page templates.html |
|
44 \title Why Doesn't Qt Use Templates for Signals and Slots? |
|
45 \brief The reasoning behind Qt's implementation of signals and slots. |
|
46 |
|
47 Templates are a builtin mechanism in C++ that allows the compiler to |
|
48 generate code on the fly, depending on the type of the arguments |
|
49 passed. As such, templates are highly interesting to framework |
|
50 creators, and we do use advanced templates in many places |
|
51 in Qt. However, there are limitations: There are things that you can |
|
52 easily express with templates, and there are things that are |
|
53 impossible to express with templates. A generic vector container class |
|
54 is easily expressible, even with partial specialisation for pointer |
|
55 types, while a function that sets up a graphical user interface based |
|
56 on a XML description given as a string is not expressible as |
|
57 template. And then there is gray area in between. Things that you can |
|
58 hack with templates at the cost of code size, readability, |
|
59 portability, usability, extensability, robustness and ultimately |
|
60 design beauty. Both templates and the C preprocessor can be stretched |
|
61 to do incredibility smart and mind boggling things. But just because |
|
62 those things can be done, does not necessarily mean doing them is the |
|
63 right design choice. |
|
64 |
|
65 There is an important practical challenge we have to mention: due to |
|
66 the inadequacies of various compilers it is still not possible to |
|
67 fully exploit the template mechanism in cross-platform |
|
68 applications. Code unfortunately is not meant to be published in |
|
69 books, but compiled with real-world compilers on real-world operating |
|
70 system. Even today, many widely used C++ compilers have problems with |
|
71 advanced templates. For example, you cannot safely rely on partial |
|
72 template specialisation, which is essential for some non-trivial |
|
73 problem domains. Some compilers also have limitations with regards to |
|
74 template member functions, which make it hard to combine generic |
|
75 programming with object orientated programming. However, we do not |
|
76 perceive these problems as a serious limitation in our work. Even if |
|
77 all our users had access to a fully standards compliant modern C++ |
|
78 compiler with excellent template support, we would not abandon the |
|
79 string-based approach used by our meta object compiler for a template |
|
80 based signals and slots system. Here are five reasons why: |
|
81 |
|
82 \section1 Syntax matters |
|
83 |
|
84 Syntax isn't just sugar: the syntax we use to express our algorithms can |
|
85 significantly affect the readability and maintainability of our code. |
|
86 The syntax used for Qt's signals and slots has proved very successful in |
|
87 practice. The syntax is intuitive, simple to use and easy to read. |
|
88 People learning Qt find the syntax helps them understand and utilize the |
|
89 signals and slots concept -- despite its highly abstract and generic |
|
90 nature. Furthermore, declaring signals in class definitions ensures that |
|
91 the signals are protected in the sense of protected C++ member |
|
92 functions. This helps programmers get their design right from the very |
|
93 beginning, without even having to think about design patterns. |
|
94 |
|
95 \section1 Code Generators are Good |
|
96 |
|
97 Qt's \c{moc} (Meta Object Compiler) provides a clean way to go |
|
98 beyond the compiled language's facilities. It does so by generating |
|
99 additional C++ code which can be compiled by any standard C++ compiler. |
|
100 The \c{moc} reads C++ source files. If it finds one or more class |
|
101 declarations that contain the Q_OBJECT macro, it produces another C++ |
|
102 source file which contains the meta object code for those classes. The |
|
103 C++ source file generated by the \c{moc} must be compiled and |
|
104 linked with the implementation of the class (or it can be |
|
105 \c{#included} into the class's source file). Typically \c{moc} |
|
106 is not called manually, but automatically by the build system, so it |
|
107 requires no additional effort by the programmer. |
|
108 |
|
109 The \c{moc} is not the only code generator Qt is using. Another |
|
110 prominent example is the \c{uic} (User Interface Compiler). It |
|
111 takes a user interface description in XML and creates C++ code that |
|
112 sets up the form. Outside Qt, code generators are common as well. Take |
|
113 for example \c{rpc} and \c{idl}, that enable programs or |
|
114 objects to communicate over process or machine boundaries. Or the vast |
|
115 variety of scanner and parser generators, with \c{lex} and |
|
116 \c{yacc} being the most well-known ones. They take a grammar |
|
117 specification as input and generate code that implements a state |
|
118 machine. The alternatives to code generators are hacked compilers, |
|
119 proprietary languages or graphical programming tools with one-way |
|
120 dialogs or wizards that generate obscure code during design time |
|
121 rather than compile time. Rather than locking our customers into a |
|
122 proprietary C++ compiler or into a particular Integrated Development |
|
123 Environment, we enable them to use whatever tools they prefer. Instead |
|
124 of forcing programmers to add generated code into source repositories, |
|
125 we encourage them to add our tools to their build system: cleaner, |
|
126 safer and more in the spirit of UNIX. |
|
127 |
|
128 |
|
129 \section1 GUIs are Dynamic |
|
130 |
|
131 C++ is a standarized, powerful and elaborate general-purpose language. |
|
132 It's the only language that is exploited on such a wide range of |
|
133 software projects, spanning every kind of application from entire |
|
134 operating systems, database servers and high end graphics |
|
135 applications to common desktop applications. One of the keys to C++'s |
|
136 success is its scalable language design that focuses on maximum |
|
137 performance and minimal memory consumption whilst still maintaining |
|
138 ANSI C compatibility. |
|
139 |
|
140 For all these advantages, there are some downsides. For C++, the static |
|
141 object model is a clear disadvantage over the dynamic messaging approach |
|
142 of Objective C when it comes to component-based graphical user interface |
|
143 programming. What's good for a high end database server or an operating |
|
144 system isn't necessarily the right design choice for a GUI frontend. |
|
145 With \c{moc}, we have turned this disadvantage into an advantage, |
|
146 and added the flexibility required to meet the challenge of safe and |
|
147 efficient graphical user interface programming. |
|
148 |
|
149 Our approach goes far beyond anything you can do with templates. For |
|
150 example, we can have object properties. And we can have overloaded |
|
151 signals and slots, which feels natural when programming in a language |
|
152 where overloads are a key concept. Our signals add zero bytes to the |
|
153 size of a class instance, which means we can add new signals without |
|
154 breaking binary compatibility. Because we do not rely on excessive |
|
155 inlining as done with templates, we can keep the code size smaller. |
|
156 Adding new connections just expands to a simple function call rather |
|
157 than a complex template function. |
|
158 |
|
159 Another benefit is that we can explore an object's signals and slots at |
|
160 runtime. We can establish connections using type-safe call-by-name, |
|
161 without having to know the exact types of the objects we are connecting. |
|
162 This is impossible with a template based solution. This kind of runtime |
|
163 introspection opens up new possibilities, for example GUIs that are |
|
164 generated and connected from Qt Designer's XML UI files. |
|
165 |
|
166 \section1 Calling Performance is Not Everything |
|
167 |
|
168 Qt's signals and slots implementation is not as fast as a |
|
169 template-based solution. While emitting a signal is approximately the |
|
170 cost of four ordinary function calls with common template |
|
171 implementations, Qt requires effort comparable to about ten function |
|
172 calls. This is not surprising since the Qt mechanism includes a |
|
173 generic marshaller, introspection, queued calls between different |
|
174 threads, and ultimately scriptability. It does not rely on excessive |
|
175 inlining and code expansion and it provides unmatched runtime |
|
176 safety. Qt's iterators are safe while those of faster template-based |
|
177 systems are not. Even during the process of emitting a signal to |
|
178 several receivers, those receivers can be deleted safely without your |
|
179 program crashing. Without this safety, your application would |
|
180 eventually crash with a difficult to debug free'd memory read or write |
|
181 error. |
|
182 |
|
183 Nonetheless, couldn't a template-based solution improve the performance |
|
184 of an application using signals and slots? While it is true that Qt adds |
|
185 a small overhead to the cost of calling a slot through a signal, the |
|
186 cost of the call is only a small proportion of the entire cost of a |
|
187 slot. Benchmarking against Qt's signals and slots system is typically |
|
188 done with empty slots. As soon as you do anything useful in your slots, |
|
189 for example a few simple string operations, the calling overhead becomes |
|
190 negligible. Qt's system is so optimized that anything that requires |
|
191 operator new or delete (for example, string operations or |
|
192 inserting/removing something from a template container) is significantly |
|
193 more expensive than emitting a signal. |
|
194 |
|
195 Aside: If you have a signals and slots connection in a tight inner loop |
|
196 of a performance critical task and you identify this connection as the |
|
197 bottleneck, think about using the standard listener-interface pattern |
|
198 rather than signals and slots. In cases where this occurs, you probably |
|
199 only require a 1:1 connection anyway. For example, if you have an object |
|
200 that downloads data from the network, it's a perfectly sensible design |
|
201 to use a signal to indicate that the requested data arrived. But if you |
|
202 need to send out every single byte one by one to a consumer, use a |
|
203 listener interface rather than signals and slots. |
|
204 |
|
205 \section1 No Limits |
|
206 |
|
207 Because we had the \c{moc} for signals and slots, we could add |
|
208 other useful things to it that could not be done with templates. |
|
209 Among these are scoped translations via a generated \c{tr()} |
|
210 function, and an advanced property system with introspection and |
|
211 extended runtime type information. The property system alone is a |
|
212 great advantage: a powerful and generic user interface design tool |
|
213 like Qt Designer would be a lot harder to write - if not impossible - |
|
214 without a powerful and introspective property system. But it does not |
|
215 end here. We also provide a dynamic qobject_cast<T>() mechanism |
|
216 that does not rely on the system's RTTI and thus does not share its |
|
217 limitations. We use it to safely query interfaces from dynamically |
|
218 loaded components. Another application domain are dynamic meta |
|
219 objects. We can e.g. take ActiveX components and at runtime create a |
|
220 meta object around it. Or we can export Qt components as ActiveX |
|
221 components by exporting its meta object. You cannot do either of these |
|
222 things with templates. |
|
223 |
|
224 C++ with the \c{moc} essentially gives us the flexibility of |
|
225 Objective-C or of a Java Runtime Environment, while maintaining C++'s |
|
226 unique performance and scalability advantages. It is what makes Qt the |
|
227 flexible and comfortable tool we have today. |
|
228 |
|
229 */ |