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