From 7f38b80fa88f9e105f7732583766033a8cc62b3a Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Mon, 24 Jan 2011 15:24:12 -0800 Subject: [PATCH] add brief intro document --- doc/Signals and Slots.lyx | 393 ++++++++++++++++++++++++++++++++++++++ doc/Signals and Slots.pdf | Bin 0 -> 10841 bytes 2 files changed, 393 insertions(+) create mode 100644 doc/Signals and Slots.lyx create mode 100644 doc/Signals and Slots.pdf diff --git a/doc/Signals and Slots.lyx b/doc/Signals and Slots.lyx new file mode 100644 index 0000000..8652b95 --- /dev/null +++ b/doc/Signals and Slots.lyx @@ -0,0 +1,393 @@ +#LyX 1.5.0beta1 created this file. For more info see http://www.lyx.org/ +\lyxformat 262 +\begin_document +\begin_header +\textclass scrartcl +\begin_preamble +\usepackage{listings} +\end_preamble +\language english +\inputencoding auto +\font_roman times +\font_sans helvet +\font_typewriter courier +\font_default_family default +\font_sc false +\font_osf false +\font_sf_scale 100 +\font_tt_scale 100 +\graphics default +\paperfontsize default +\spacing single +\papersize default +\use_geometry false +\use_amsmath 1 +\use_esint 1 +\cite_engine basic +\use_bibtopic false +\paperorientation portrait +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation indent +\defskip medskip +\quotes_language english +\papercolumns 1 +\papersides 1 +\paperpagestyle default +\tracking_changes false +\output_changes false +\author "swaits" +\end_header + +\begin_body + +\begin_layout Title +Signals and Slots +\end_layout + +\begin_layout Author +Stephen Waits +\end_layout + +\begin_layout Date +November 10, 2006 +\end_layout + +\begin_layout Abstract +This brief document provides an overview of the event and message handling + system written for and used in the SCEA NBA PSP projects. +\end_layout + +\begin_layout Section +Goals +\end_layout + +\begin_layout Itemize +Basic synchronous messaging +\end_layout + +\begin_layout Itemize +Decouple game modules +\end_layout + +\begin_layout Itemize +Appropriate parameter handling (i.e. + no blind parms, casting parms, etc.) +\end_layout + +\begin_layout Itemize +Ease of use +\end_layout + +\begin_layout Itemize +Lightweight +\end_layout + +\begin_layout Itemize +Strive for elegant, clean, readable, and maintainable code +\end_layout + +\begin_layout Section +History +\end_layout + +\begin_layout Standard +When I started researching event messaging systems and libraries in early + 2004, I initially looked at what Qt and other similar libraries used. + I ended up discovering libsigc++, which was my introduction to the signal/slot + concept. + Unfortunately, libsigc++, while fascinating, was much too big for my needs, + so, I set out to write my own, simpler, lighter library. +\end_layout + +\begin_layout Standard +Once I got the library predominately functional, we integrated it into our + codebase. + I found that it took very little explanation to bring other programmers + up to speed on the concepts and practical use of signals and slots. + After using them for a bit, everyone on the team agreed that we had benefited + greatly from adopting this simple concept throughout our code. + The signals rocked for us. +\end_layout + +\begin_layout Standard +Today, I can confidently say that this single library alone bears great + responsibility in the overall cleanliness and readability of our codebase. + Without it, we'd have a giant pile of spaghetti by now. + Instead, we have clear, simple, decoupled systems which all communicate + via a common interface. +\end_layout + +\begin_layout Section +Usage +\end_layout + +\begin_layout Standard +Signals are effectively emitters. + Slots are effectively callback functions, methods, or functors. +\end_layout + +\begin_layout LyX-Code +\begin_inset ERT +status open + +\begin_layout Standard + + +\backslash +lstset{language=C++} +\end_layout + +\begin_layout Standard + + +\backslash +begin{lstlisting} +\end_layout + +\begin_layout Standard + +// create a signal +\end_layout + +\begin_layout Standard + +Signal< void, int /* x */, int /* y */ > OnClick; +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard + +// A function matching the signal's type +\end_layout + +\begin_layout Standard + +// (returns void, accepts 2 ints) +\end_layout + +\begin_layout Standard + +void beep(int x, int y) { ... + } +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard + +// A class method matching the signal's type +\end_layout + +\begin_layout Standard + +// (returns void, accepts 2 ints) +\end_layout + +\begin_layout Standard + +struct Bark { void woof(int x, int y); } +\end_layout + +\begin_layout Standard + +Bark barker; +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard + +// connect a regular function +\end_layout + +\begin_layout Standard + +OnClick.Connect( beep ); // beep becomes a Slot +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard + +// connect a member of a specific object +\end_layout + +\begin_layout Standard + +OnClick.Connect( &barker, &Bark::woof ); // woof is a Slot +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard + +// emit +\end_layout + +\begin_layout Standard + +OnClick(10,20); // calls beep(10,20) and barker.woof(10,20) +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard + +// disconnect +\end_layout + +\begin_layout Standard + +OnClick.Disconnect( beep ); +\end_layout + +\begin_layout Standard + +OnClick.Disconnect( &barker, &Bark::woof ); +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard + +// note that this won't compile (type safety) +\end_layout + +\begin_layout Standard + +void badbeep(int x, float y); // parameter mismatch +\end_layout + +\begin_layout Standard + +OnClick.Connect( badbeep ); // compile-time error! +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout Standard + + +\backslash +end{lstlisting} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +In Practice +\end_layout + +\begin_layout Standard +In our projects, we primarily use signals in two ways. +\end_layout + +\begin_layout Standard +First, we maintain a master list of global signals. + These handle things such as a player stepping out of bounds, the ball hitting + the backboard, a team calling timeout, and, basically everything that happens + in basketball. + This list of signals has grown quite large, but remains organized. +\end_layout + +\begin_layout Standard +Second, some classes include public signals. + For example, class Clock might have a public signal named "Changed" which + gets emitted any time its internal time is updated. + The Clock object doesn't have to care if anyone connects - its responsibility + ends at emission. + Our UI system also makes heavy use of signals. +\end_layout + +\begin_layout Section +Summary +\end_layout + +\begin_layout Subsection +Positives +\end_layout + +\begin_layout Itemize +Simple code is easy to use +\end_layout + +\begin_layout Itemize +Emitter/Subscriber model is rather nice to use and allows for massive decoupling +\end_layout + +\begin_layout Itemize +Synchronous emission +\end_layout + +\begin_layout Itemize +Static type safety (this is a huge plus!!!) +\end_layout + +\begin_layout Itemize +Very easy to add to your project (it's almost entirely a template library) +\end_layout + +\begin_layout Subsection +Negatives +\end_layout + +\begin_layout Itemize +Current implementation does use some dynamic memory +\end_layout + +\begin_layout Itemize +Requires RTTI +\begin_inset Foot +status open + +\begin_layout Standard +RTTI is commonly thought to be the devil amongst uninformed game programmers; + however, the only expense is one of a very slight size increase. + Performance, possible slight caching consequences aside, generally remains + the same. + The convenience, in my opinion, vastly outweighs the cost. +\end_layout + +\end_inset + +; though only on Connect/Disconnect/IsConnected calls (normally infrequent) +\end_layout + +\begin_layout Itemize +Not a negative to most, but does use some template-fu to keep things easy + on the outside +\end_layout + +\begin_layout Itemize +Related to the template-fu, they can bloat; however, we've done our best + to minimize this +\end_layout + +\begin_layout Itemize +Return value heuristic never reached (i.e. + what does the emitter return when calling multiple slots?) +\end_layout + +\end_body +\end_document diff --git a/doc/Signals and Slots.pdf b/doc/Signals and Slots.pdf new file mode 100644 index 0000000000000000000000000000000000000000..30fe919c2512c3e09fafb3ccd081e556522b36d7 GIT binary patch literal 10841 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 DIz(x% literal 0 HcmV?d00001