/* */ /* */

Wednesday, May 22, 2013

Lambdas vs. Closures

In recent days, I've twice found myself explaining the difference between lambdas and closures in C++11, so I figured it was time to write it up.

The term "lambda" is short for lambda expression, and a lambda is just that: an expression. As such, it exists only in a program's source code. A lambda does not exist at runtime.

The runtime effect of a lambda expression is the generation of an object. Such objects are known as closures.

Given

  auto f = [&](int x, int y) { return fudgeFactor * (x + y); };

the blue expression to the right of the "=" is the lambda expression (i.e., "the lambda"), and the runtime object created by that expression is the closure.

You could be forgiven for thinking that, in this example, f was the closure, but it's not. f is a copy of the closure. The process of copying the closure into f may be optimized into a move (whether it is depends on the types captured by the lambda), but that doesn't change the fact that f itself is not the closure. The actual closure object is a temporary that's typically destroyed at the end of the statement.

The distinction between a lambda and the corresponding closure is precisely equivalent to the distinction between a class and an instance of the class. A class exists only in source code; it doesn't exist at runtime. What exists at runtime are objects of the class type.  Closures are to lambdas as objects are to classes. This should not be a surprise, because each lambda expression causes a unique class to be generated (during compilation) and also causes an object of that class type--a closure--to be created (at runtime).

Scott

PS - I noted above that a closure is typically destroyed at the end of the statement in which it is created.  The exception to this rule is when you bind the closure to a reference. The simplest way to do that is to employ a universal reference,

  auto&& rrefToClosure = [&](int x, int y) { return fudgeFactor * (x + y); };

but binding it to an lvalue-reference-to-const will also work:

  const auto& lrefToConstToClosure = [&](int x, int y) { return fudgeFactor * (x + y); };

Monday, May 6, 2013

C++14 Lambdas and Perfect Forwarding

So the joke's on me, I guess.

In my discussion of std::move vs. std::forward, I explained that when you call std::forward, the expectation is that you'll pass a type consistent with the rules for template type deduction, meaning (1) an lvalue reference type for lvalues and (2) a non-reference type for rvalues.  I added,
If you decide to be a smart aleck and write [code passing an rvalue reference type], the reference-collapsing rules will see that you get the same behavior as [you would passing a non-reference type], but with any luck, your team lead will shift you to development in straight C, where you'll have to content yourself with writing bizarre macros.
Well.  As I said, the joke seems to be on me, because the standardization commitee  apparently consists largely of smart alecks.

Let me explain.

The recently-adopted C++14 CD includes beefy additions to lambda capabilities, including the support for polymorphic lambdas that Herb Sutter can't help but mention I've been whining about for years. This means that in C++14, we now have the expressive power that the Boost Lambda library has been offering since 2002. Ahem. But C++14 goes further, supporting also variadic lambdas, generalized captures (including capture-by-move), and, of particular relevance to this post, support for perfect forwarding.

Suppose we want to write a C++14 lambda that takes a parameter and perfect-forwards it to some function f:
auto forwardingLambda = [](auto&& param) { /* perfect-forward param to f */ };
Writing the perfect-forwarding call is easy, but it's probably not obvious how.  The normal way to perfect-forward something it to use std::forward, so we'd expect to write essentially this:
auto forwardingLambda = [](auto&& param) { f(std::forward<T>(param)); };
But, uh oh, there's no T to pass to std::forward.  (In the class generated from the lambda expression, there is, but inside the lambda itself, there's no type for param.)  So what do we pass to std::forward? We can hardly pass auto. (Consider what would happen if we had a lambda taking multiple parameters, each of type auto and each of which we wanted to forward. In that case, each std::forward<auto> would be ambiguous: which auto should std::forward use?)

The solution takes advantage of two observations. First, the type-deduction rules for auto in lambdas are the same as for templates. This means that if an lvalue argument is passed to the lambda, param's type will be an lvalue reference--exactly what we need for std::forward. If an rvalue argument is passed, its type will be an rvalue reference. For such parameters, we can recover the type to pass to std::forward by stripping it of its reference-ness. We could thus write forwardingLambda like this:
auto forwardingLambda = [](auto&& param) {
  f(std::forward<std::conditional<std::is_rvalue_reference<decltype(param)>::value,
                                  std::remove_reference<decltype(param)::type,
                                  decltype(param)>::type>(param));
};

At least I think we could. I don't have a C++14 compiler to try it with, and, anyway, it's too gross to waste time on. It would be sad, indeed, if this is what the standardization committee expected us to do to effect perfect forwarding inside its spiffy new C++14 lambdas. Fortunately, it doesn't.

Which brings us to observation number two. As I noted near the beginning of this post,
If you decide to be a smart aleck and write [code passing an rvalue reference type to std::forward], the reference-collapsing rules will see that you get the same behavior as [you would passing a non-reference type].
That means that if param's type is an rvalue reference, there is no need to strip off its reference-ocity. Instead, you can smart aleck your way to success by simply passing that type directly to std::forward.  Like so:
auto forwardingLambda = [](auto&& param) { f(std::forward<decltype(param)>(param)); };
Frankly, this is more verbose than I'd prefer. One could imagine a world where you could say something like this:
auto forwardingLambda =
  [](<T1>&& param1, <T2>&& param2) { f(std::forward<T1>(param1), std::forward<T2>(param2)); };
But that's not the world we live in, and given that C++14 gives us polymorphic lambdas, variadic lambdas, and move-enabled lambdas, I'm not going to complain about the world of C++14 lambdas.  Except possibly to Herb :-)

Scott

Shared State from std::async remains special

In an earlier post, I pointed out that, contrary to the way things are generally described, it's not the futures returned from std::async that are special, it's the shared state they refer to that is. In the comments that followed that post, it was pointed out that this could change in C++14, but the proposal to that effect was rejected at the standardization committee meeting last month. As Anthony Williams put it in his blog post,
Herb Sutter's late paper on the behaviour of the destructor of std::future (N3630) was up next. This is a highly conterversial topic, and yielded much discussion. The crux of the matter is that as currently specified the destructor of std::future blocks if it came from an invocation of std::async, the asynchronous function was run on a separate thread (with the std::launch::async policy), and that thread has not yet finished.
[...]
 Much of the discussion focused on the potential for breaking existing code, and ways of preventing this. The proposal eventually morphed into a new paper (N3637) which created 2 new types of future: waiting_future and shared_waiting_future. std::async would then be changed to return a waiting_future instead of a future. Existing code that compiled unchanged would then keep the existing behaviour; code that changed behaviour would fail to compile. Though the change required to get the desired behaviour would not be extensive, the feeling in the full committee was that this breakage would be too extensive, and the paper was also voted down in full committee.
C++14 now has CD ("committee draft") status, but that doesn't mean things can't change. A member of the committee emailed me as follows:
[The] paper on changing [the behavior of futures referring to shared state from std::async] was rejected, after a LOT of discussion. The discussion has continued on the reflector, and we may get a NB comment on the C++14 draft about it, but for now there is no change.
My impression is that many committee-watchers had considered a change in the specification for std::async to be a sure thing, but, as I wrote in yet another blog post, the committee tends to be quite conservative about the possibility of breaking existing code. At this point, that looks to be the line they're going to follow as regards the behavior of (the shared state corresponding to) futures produced by std::async.

Scott

Friday, April 5, 2013

Draft TOC for EC++11 Concurrency Chapter

A couple of months ago, I posted a draft Table of Contents (TOC) for Effective C++11. At that point, the entries for the concurrency chapter were so rough, they weren't even in the form of guidelines. Now they are, and I'm pleased to unveil my first draft TOC for the chapter on concurrency support:
  • Create tasks, not threads.
  • Pass std::launch::async if asynchronicity is essential.
  • Make std::threads unjoinable on all paths.
  • Be aware of varying thread handle destructor behavior.
  • Consider void futures for one-shot event communication.
  • Pass parameterless functions to std::thread, std::async, and std::call_once.
  • Use std::lock to acquire multiple locks.
  • Prefer non-recursive mutexes to recursive ones.
  • Declare future and std::thread members last.
  • Code for spurious failures in try_lock, condvar wait, and weak CAS operations.
  • Distinguish steady from unsteady clocks.
  • Use native handles to transcend the C++11 API.
  • Employ sequential consistency if at all possible.
  • Distinguish volatile from std::atomic.
This is a draft TOC. There's nothing final about the presence, order, or wording of these Items. Furthermore, unless either your mind-reading skills are better than I expect or my mind is easier to read than I fear, it will be tough for you to anticipate what I plan to say in these Items based only on the Item titles. Still, if you see advice above that you think is either especially good or especially bad, don't be shy about letting me know about it.

I'm especially pleased with the first Item on the list ("Create tasks, not threads"), because when I came up with that wording, a number of up-to-that-point disparate thoughts fell into place with a very satisfying thud.

When I began that Item, the only thing I knew I wanted to talk about was that thread construction can throw.  In Effective C++, Second Edition, my advice about dealing with the fact that operator new can throw is "Be prepared for out-of-memory conditions," so I started thinking about guidance such as "Be prepared for std::thread exhaustion." But what does it mean to be prepared to run out of threads? With operator new, there's a new handler you can configure. There's nothing like that for thread creation. And if you request n bytes from operator new and you can't get it, you may be able to scale down your request to, say, n/2 bytes, then try again. But if you request a new thread and that fails, what are you supposed to do, request half a thread?

I didn't like where that was going.  So I decided to think about avoiding the problem of running out of threads by not requesting them directly.  The prospective guideline "Prefer std::async to std::thread" had been an elephant in the room from the beginning, so I started playing with that idea.  But one of the other guidelines I was considering was "Pass std::launch::async if asynchronicity is essential" (it's on the draft TOC above), and the spec for std::async says that it throws the same exception as the std::thread constructor if you pass std::launch::async as the launch policy and std::async can't create a new thread. So advising people to use std::async was not sufficient, because using std::async with std::launch::async is no better than using std::thread for purposes of avoiding out-of-thread exceptions.

Though my primary focus had been on figuring out how to avoid exceptions due to too many threads, another issue I wanted to address was how to deal with oversubscription: creating more threads than can efficiently run on the machine. The way to avoid that problem is to use std::async with the default launch policy, and that got me to thinking about what to call a function (or function object--henceforth simply a "function") that could be run either synchronously or asynchronously.  A raw function doesn't qualify, because if you run a raw function asynchronously on a std::thread, there is no way to get the result of the function.  (And if the function throws an exception, std::terminate gets called.) Fortunately, C++11 offers a way to prepare a function for possible asynchronous execution: wrap it in std::packaged_task. How fortuitous! I had been looking for an excuse to discuss std::packaged_task, and its existence allowed me to assign a C++11 meaning to the otherwise squishy notion of a "task".

Thus the (still tentative) Item title was born.

What I really like about it is that it's both design advice and coding advice.  At a design level, creating tasks means developing independent pieces of functionality that may be run either synchronously or asynchronously, depending on the computational resources dynamically available on the machine.  At a coding level, it means taking functions and making them suitable for asynchronous execution, either by wrapping them with std::packaged_task or, preferably, by submitting them to std::async (which does the wrapping for you).

"Create tasks, not threads" thus gives me a context in which to discuss exceptions thrown by thread creation requests, the problem of oversubscription, std::thread, std::async, std::packaged_task, and tasks versus threads. Along the way I also get to discuss thread pools and the conditions under which it can make sense to bypass tasks and go straight to std::threads. (Can you see a cross-reference to "Use native handles to transcend the C++11 API"?  I can.)

Scott

Monday, March 25, 2013

Thread Handle Destruction and Behavioral Consistency

Suppose you fire up a thread in a function, then return from the function without joining or detaching the thread:
void doSomeWork();

void f1()
{
  std::thread t(doSomeWork);
  ...                          // no join, no detach
}
What happens?

Your program is terminated. The destructor of a std::thread object that refers to a "joinable" thread calls std::terminate.

Now suppose you do the same thing, except instead of firing up the thread directly, you do it via std::async:
void f2()
{
  auto fut = std::async(std::launch::async, doSomeWork);
  ...                          // no get, no wait
}
Now what happens?

Your function blocks until the asychronously running thread completes. This is because the shared state for a std::async call causes the last future referring to that shared state to block in its destructor. Practically speaking, the destructor for the final future referring to a std::async shared state does an implicit join on the asynchronously running thread.

(The behavior I'm describing is mandated by the standard. Some implementations, notably Microsoft's, don't behave this way, because the standardization committee is considering changing this aspect of the standard, and Microsoft has implemented the revised behavior they believe will ultimately be adopted.)

Finally, suppose you create a packaged_task for the function to be run asynchronously, then you detach from the thread running the packaged_task, while retaining the future for the packaged_task:
void f3()
{
  std::packaged_task<void()> pt(doSomeWork);
  auto fut = pt.get_future();
  std::thread(std::move(pt)).detach();
  ...                          // no get, no wait
}
Now what happens?

Your function returns, even if the function to be run asynchronously is still running. In essence, the thread is detached. The destructor of the thread object no longer refers to a joinable thread (thanks to the call to detach), so it doesn't call std::terminate, and the destructor of the std::future refer doesn't refer to a shared state for a call to std::async, so it doesn't performs an implicit join.

"So what's your point?," you may be wondering. Well, we can think of both std::thread objects and futures as handles for asynchronously running threads, and it's interesting to note that when such handles are destroyed, in some cases, we terminate, in others we do an implicit join, and in others we do an implicit detach. As I've been known to put it, the standardaization committee, when faced with a choice of three possible behaviors, chose all three.

In fact, I'm making this post at the request of a member of the standardization committee who thought it would be worthwhile to point out this inconsistency in the standard's treatment of thread handles. Whether anything will be done about it remains to be seen. If the specification for std::async is modified such that its shared state no longer causes the blocking behavior I described in my last post, that would eliminate the implicit join behavior, but I'm not convinced that such a change is a shoe-in for adoption. The problem is that such a change to the standard could silently break the behavior of existing programs (i.e., code that depends on the implicit join in future destructors that are the final reference to a shared state coming from std::async), and the standardization committee is generally very reluctant to adopt changes that can silently change the behavior of conforming programs.

Scott




Wednesday, March 20, 2013

std::futures from std::async aren't special!

This is a slightly-revised version of my original post. It reflects information I've since received that confirms some of the suppositions I'd been making, and it rewords some things to clarify them.


It's comparatively well known that the std::future returned from std::async will block in its destructor until the asynchronously running thread has completed:
void f()
{
  std::future<void> fut = std::async(std::launch::async, 
                                     [] { /* compute, compute, compute */ });

}                                    // block here until thread spawned by
                                     // std::async completes
Only std::futures returned from std::async behave this way, so I had been under the impression that they were special. But now I believe otherwise. I now believe that all futures must behave the same way, regardless of whether they originated in std::async. This does not mean that all futures must block in their destructors. The story is more nuanced than that.

There's definiately something special about std::async, because futures you get from other sources (e.g., from a std::promise or a std:: packaged_task) don't block in their destructors.  But how does the specialness of std::async affect the behavior of futures?

C++11 futures are the caller's end of a communications channel that begins with a callee that's (typically) called asynchronously. When the called function has a result to communicate to its caller, it performs a set operation on the std::promise corresponding to the future.  That is, an asynchronous callee sets a promise (i.e., writes a result to the communication channel between it and its caller), and its caller gets the future (i.e., reads the result from the communications channel).

(As usual, I'm ignoring a host of details that don't affect the basic story I'm telling.  Such details including return values versus exceptions, waiting versus getting, unshared versus shared futures, etc.)

Between the time a callee sets its promise and its caller does a corresponding get, an arbitrarily long time may elapse. (In fact, the get may never take place, but that's a detail I'm ignoring.) As a result, the std::promise object that was set may be destroyed before a get takes place.  This means that the value with which the callee sets the promise can't be stored in the promise--the promise may not have a long enough lifetime.  The value also can't be stored in the future corresponding to the promise, because the std::future returned from std::async could be moved into a std::shared_future before being destroyed, and the std::shared_future could then be copied many times to new objects, some of which would subsequently be destroyed. In that case, which future would hold the value returned by the callee?

Because neither the promise nor the future ends of the communications channel between caller and callee are suitable for storing the result of an asynchronously invoked function, it's stored in a neutral location. This location is known as the shared state.  There's nothing in the C++ standard library corresponding to the shared state.  No class, no type, no function. In practice, I'm guessing it's implemented as a class that's templatized on at least the type of the result to be communicated between callee and caller.

The special behavior commonly attributed to futures returned by std::async is actually determined by the shared state. Once you know what to look for, this is indicated in only moderately opqaque prose (for the standard) in 30.6.8/3, where we learn that
The thread object [for the function to be run asynchronously] is stored in the shared state and affects the behavior of any asynchronous return objects [e.g., futures] that reference that state.
and in 30.6.8/5, where we read:
the thread completion [for the function run asynchronously] synchronizes with [i.e., occurs before] [1] the return from the first function that successfully detects the ready status of the shared state or [2] with the return from the last function that releases the shared state, whichever happens first.
It's provision [2] that's relevant to us here. It tells us that if a future holds the last reference to the shared state corresponding to a call to std::async, that future's destructor must block until the thread for the asynchronously running function finishes. This is a requirement for any future object. There is nothing special about std::futures returned from std::async. Rather, the specialness of std::async is manifested in its shared state.

By the way, when I write that the "future's destructor must block," I don't mean it literally. The standard just says that the function releasing the last reference to a shared state corresponding to a std::async call can't return as long as the thread for the asynchronously running function is still executing. That behavior doesn't have to be implemented by having a future's destructor directly block. The future destructor might simply call a member function to decrement the reference count on the shared state. Inside that call, if the result of the decrement was zero and the shared state corresponded to a std::async call, the member function would simply wait until the thread running the asynchronously running function completed before it returned to the future destructor.  From the future's point of view, it merely made a synchronous call to a function to decrement the reference count on the shared state.  The runtime behavior, however, would be that it could block until the asynchronously running thread completed.

The provision stating that, essentially, the shared state corresponding to a call to std::async must somehow indicate that the last future referring to them must block until the associated thread has finished running, is not popular. It's been proposed to be changed, and some standard library implementations (e.g., Microsoft's) have already revised their implementations to eliminate the "futures from std::async block in their destructors" behavior. That makes it trickier for you to test the behavior of this part of the standard, because the library you use may be deliberately nonconformant in this area.

Scott

PS - The reason I got caught up in this matter was that I was trying to find a way to perform the moral equivalent of a detach on a thread spawned via std::async.  Because I believed it was the std::future returned from std::async that was special, I started experimenting with things like moving that std::future into a std::shared_future in an attempt to return from the function calling std::async before the asynchronously running function had finished. But since it's the shared state that's special, not the std::future, this approach seems doomed. If you know how to get detach-like behavior when using std::async (without the cooperation of the function being run asynchronously), please let me know!

Wednesday, March 13, 2013

The Line-Length Problem

The bane of publishing code for consumption on a variety of platforms is that the available horizontal space varies.  I've blogged elsewhere that I want to avoid horizontal scrolling or bad line breaks in code, and I'm working with my publisher on how to do that. I'd like your help, too.

My understanding is that on Kindle and iPad (the platforms for which I currently have some data), the size of the text you see depends on both the font size specified in the document's CSS (which you, as a reader, typically can't control) as well as on the font size specified for the device (which you, as a reader, typically can).  The response to my earlier post about font choices showed a marked preference for code in a fixed-pitch font, so that's what I plan to use in Effective C++11. I've received the following information regarding how many characters fit on a line in Kindle and iPad in various combinations of device and CSS font sizes and device orientations:
It's interesting that on iPad, using the device in landscape mode shows two columns instead of one, thus providing less horizontal line space per line. As an author, this means I actually have more room to work with when the device is used in portrait mode.

As you can see, if I limit my code displays to 45 characters per line, that should display without problems under all but two combinations of settings above.  I think that 45 characters per line would look strange on devices with more horizontal room, however, and the data also show that for many combinations of settings, I could use up to 60 characters per line (which is about what I'd have in a printed book).  Not being a fan of lowest-common-denominator constraint satisfaction (i.e., not penalizing people with devices and settings for wider lines for the benefit of people with devices and settings for narrower lines) my thought is that I'll format my code displays twice, once with no more than 45 characters/line and once with up to 60. As an example of what that could mean in real life, here's some sample code from Item 3 of the current (third) edition of Effective C++. As is all code in that book, it's in a proportional font:

Here it is formatted in a fixed-pitch font with no more than 60 characters/line:
class TextBlock {  
public:
  ...  

  const char&
  operator[](std::size_t position) const   // operator[] for
  { return text[position]; }               // const objects

  char&
  operator[](std::size_t position)       // operator[] for
  { return text[position]; }             // non-const objects

private:
  std::string text;  
};
And here it is again with no more than 45 characters/line:
class TextBlock {  
public:
  ...  

  // operator[] for const objects
  const char&
  operator[](std::size_t position) const
  { return text[position]; }

  // operator[] for non-const objects
  char& operator[](std::size_t position)
  { return text[position]; }

private:
  std::string text;  
};
Do you think it's worth my formatting code displays twice, once for wide lines and once for narrow ones, or do you think that using narrow formatting everywhere would suffice? Don't worry about how much work it is for me. That's my problem. Focus on what would work better for you.

Assuming for the moment that formatting the code twice is preferable, there's a logistical issue that has to be addressed, namely, how to write a single manuscript that can generate documents with one of two sets of code displays. My plan had been to use Microsoft Word and to use conditional text to switch between code displays, i.e., to set up "wide" and "narrow" configurations and hide the code displays that did not correspond to the current configuration. Alas, Microsoft Word 2010 (the version I'm using) lacks support for conditional text, something that quite surprised me, because both FrameMaker and OpenOffice/LibreOffice have had it for years.  Switching to a different document authoring system leads to new problems, because the publication process likely to be followed by my book is likely to involve Microsoft Word as the point of entry, meaning that even if I produce my manuscript using, say, OpenOffice, that's likely to be converted into Word as step 0, so what Word can't represent is likely to be troublesome. (Before you bombard me with suggestions to use LaTeX or some other markup language, I'm on record as viewing those as inferior to WYSIWYG systems, as I detail here.)

Do you have any ideas about how I should approach the production of code displays that look good on all "reasonable" publication platforms and that can reasonably be produced and maintained by my authoring tool, which is highly likely to be Word 2010?

Thanks,

Scott


Friday, March 1, 2013

C++ and Beyond 2013 Registration has Begun!

Registration for this year's C++ and Beyond with me, Herb Sutter, and Andrei Alexandrescu is now open! Participation is limited to 64 developers. That's about two-thirds the demand of prior years, which means that not only will C&B 2013 sell out, it's likely to sell out quickly.

For details on this year's C++ and Beyond, consult its web site. Bottom line? If you're interested in joining a small group of developers as well as me, Herb, and Andrei for three intense days of C++ and C++-related topics December 9-12  at the Salish Lodge and Spa near Seattle, you'll want to register soon.

I look forward to seeing you there!

Scott

Saturday, February 23, 2013

Schulungsunterlagen zur Anwendung von C++ in Embedded Systems stehen zur Verfügung

[If you don't read German, this post is of no interest to you, sorry. If you're dying to know what follows, plop the text into Google Translate.]

2011 habe ich zum ersten Mal mein Seminar zum Thema die effektive Anwendung von C++ in Embedded Systems auf Deutsch gehalten. Das Seminar ist ziemlich gut gegangen, denke ich (niemand ist gestorben), aber nach dem Seminar war es mir klar, dass die deutsche Version des Seminars keine Vorteile im Vergleich zu der englischen Version hat, auch wenn die Teilnehmer aus deutschsprachigen Ländern kommen.  Es scheint, dass die an diesem Thema interessierten Entwickler entweder kein Problem mit Englisch haben oder sie sogar eine Vorliebe für technische Seminare auf Englisch haben. Die erste Präsentation dieses Seminars war deshalb auch die letzte.


Ich habe nun Unterlagen für ein Seminar, welches ich nicht vorhabe, je wieder anzubieten. Ich könnte sie auf meiner Festplatte liegen lassen, aber das dient niemandem. Obwohl sie nicht mehr so ganz aktuell wie die entsprechenden Unterlagen auf Englisch sind, und obwohl die Sprache in der Unterlagen gar nicht perfekt ist (ich habe Hilfe mit der Übersetzungsarbeit bekommen, und in einigen Stellen ist es klar, dass es besser gewesen wäre, hätte ich mehr Hilfe gekriegt), denke ich, dass es trotzdem nützliche Informationen in den Folien gibt. Ich habe mich deswegen entschlossen, die Unterlagen im Internet zu veröffentlichen. Sie sind hier zu finden.

Falls Sie Interesse an der Anwendung von C++ (hauptsächlich C++98) im Embedded-Bereich haben, schlage ich vor, dass Sie meine Unterlagen probieren. Wenn Sie finden, dass sie hilfreich sind, freut das mich. Falls Sie finden, dass sie nicht hilfreich sind, tut es mir leid, aber Sie können sich damit trösten, dass sie kostenlos sind :-)

Scott

Wednesday, February 13, 2013

Draft EC++11 Item

One of the most important reality checks I use to evaluate material I'm thinking about publishing is to use it in a training setting. Present a prospective guideline to a gaggle of professional C++ software developers, and you find out pretty quickly whether it comprises useful and practical advice. A prospective guideline I have for Effective C++11 is
Declare overriding functions override
I've drafted training slides for this guideline, and I'd like you to take a look and let me know what you think. (Links are at the end of this post.)

I don't normally ask for public feedback on material in the form of training slides, but in this case, I'd like to know what you think about some formatting decisions I'm in the process of making. I don't want to put a lot of effort into a manuscript only to find out later that I botched my choice of formatting options.

For over a decade, I've used a proportional font for my code examples.  Such a font uses differing widths for different characters.  An "m" is much wider than an "i", for example.  This has the advantage that I can get a lot more characters on a line, which is important when I'm trying to shoehorn commented code into pages or columns of relatively narrow width. It has the disadvantage that most programmers use a fixed-pitch font (one where all the characters are the same width), so the code I publish doesn't look like what they see in their daily work. In the example I'm making available, I'm using a fixed-pitch font, e.g.:
In a proportional font, it would look like this:
For a more extensive example of code in a proportional font, take a look at my C++11 training materials sample.

 Question #1: Do you have a preference which is used in the technical material you read?


Whenever I've had multiple colors for code at my disposal, I've used blue for "normal" code and red as a highlight color (see "const" in the code examples above). Setting aside the specific color choices (which have drawbacks, both for color-blind readers and when printed on monochrome printers), the key point is that I've used two colors for code. An obvious alternative is use multiple colors to syntax-highlight the code, then find another means to highlight important sections.  One approach is to mimic highlighting pens by using yellow as a background color.  This is what was done with my Universal References article at isocpp.org:


Another approach is to use bold face to indicate highlighted code sections.  Here's that approach applied to the first code fragment I showed above:
 Question #2: What approach to code coloring do you prefer?
  • One color for "normal" code, a second color for highlighted code.
  • Syntax-colored code with yellow highlighting.
  • Syntax-colored code with bold highlighting.
It's hard to form an opinion without more than the tiny code fragments I've used in this blog post, of course, so please take a look at my draft Item for "Declare overriding functions override." It's available in two versions:
I realize that's not all possible combinations of choices, but putting together the various combinations is more work than you might imagine.  That's why I've provided links to other examples where I've used different combinations of choices.

Please let me know what you think about the formatting choices I've described.  Of course, I welcome comments on the technical content, too :-)

Thanks for your help with this.

Scott

Monday, February 11, 2013

Public Presentations in 2013

I've just updated my Upcoming Talks page with the public presentations that are currently scheduled for 2013.  Most of them will take place in Europe (Oslo and London in June, and Stuttgart in November), but there are additional U.S. events in the works, so my talks at C++ and Beyond in December are unlikely to remain my only public presentations in the USA.

Of particular note is that I'll be giving presentations of my all-new-and-still-under-development seminar, Effective C++11 Programming, in Oslo, London, and Stuttgart, and there's a good chance that at least some of my talks at C++ and Beyond will focus on the effective use of features found only in C++11.  In view of the fact that my big project for this year is writing Effective C++11 (see this post and this one for details), it should come as no surprise that that topic will be a leitmotif for 2013.

As always, details of my upcoming public presentations are to be found at my Upcoming Talks page.

I hope to see you at at least one of my presentations this year.

Scott

C++ & Beyond 2013 Dates Announced: December 9-12

The official announcement about dates and location for C++ and Beyond 2013 just went out on the C&B Blog.  They're December 9-12 at the Salish Lodge in Snoqualmie, Washington, USA (not far from Seattle).

This fourth incarnation of C&B will harken back to its roots, in the sense that we're returning to our original venue, and we're also reinstituting some of the features of the initial C&B that had changed in the past couple of years.

For more details, please consult the official announcment on the C&B blog.

Scott

Tuesday, January 29, 2013

Effective C++11: Content and Status

Before I summarize the Items I currently plan to include in Effective C++11 ("EC++11"), I'd like to explain a little about how I come up with the guidelines in my books.

It'd be sweet to imagine that I develop all the guidelines myself. If you're very technical about it, I do. I come up with all my own Item wordings, and I write all my own Item justifications. But the ideas behind the guidelines have generally already fought their way to acceptance in the C++ community. It's this acceptance that gives me confidence that the advice in the guidelines is both accurate and useful. My Effective books strive to summarize practices that are known to be effective, not to introduce new practices I hope will be.

In the case of C++11, the Standard is only about 18 months old, and some parts of it are yet to be implemented by major compilers. The experience with C++11 that is necessary to identify useful advice is therefore limited. But even the features that have not seen widespread use have been discussed and debated for years, and sometimes that gives rise to "observations" about those features that seem likely to be important. Consider, for example, what happens in a destructor for a std::future. If the future came from std::async, the future's destructor blocks until the asynchronously running thread completes. If the future did not come from std::async, the future's destructor doesn't block. That's already interesting, but, in my mind, it becomes even more interesting when combined with the observation that the destructor for a "joinable" std::thread calls the terminate function.  So we have three different behaviors for a single high-level concept: destruction of the object "responsible" for another thread.

I think this divergent behavior is likely to trip people up, and that gets it on my candidate list for EC++11. But what is the Item?  What is the advice? I could go with the lame-o "Understand destructor behavior in std::future and std::thread," but that's just cloaking an excuse to describe language rules in guideline form. I'm not above doing that when I can't think of anything better, but I prefer to find a way to offer advice that could be checked by a tool or in a code review. "Understand" rules fail that test.

(As an aside, the behavior of the destructors for std::futures produced by std::async is controversial and may change in the next revision of C++ (currently forecast to be in 2014). Some implementations already deviate from the behavior dictated by the Standard. That muddies the water yet further, but that's a problem for me and my book, not this blog post.)

You can think of "observations" about C++11 as proto-Items. They're not yet in guideline form, but they seem important enough to justify trying to find a way to work them into the book. Whether they'll make the book, and, if so, whether they'll do it as a standalone Item or as a side-discussion in another Item, I don't yet know.

At last year's C++ and Beyond, I gave a talk entitled "Initial Thoughts on Effective C++11." It had my usual guideline format. I also gave a talk on "Secrets of the C++11 Threading API," which consisted of observations about C++11's threading support.The material in those talks, combined with the feedback I got from giving them and mixed in with my experience explaining the idea of universal references, ultimately yielded the initial list of candiate Items for EC++11. The current snapshot of my vision for Effective C++11 is:

Moving from C++98 to C++11

  • Prefer auto to explicit type declarations.
  • Remember that auto + { expr }std::initializer_list.
  • Prefer nullptr to 0 and NULL.
  • Prefer enum classes to enums.
  • Prefer alias templates to typedefs.
  • Declare overriding functions override.
  • Distinguish () and {} when creating objects.
  • Prefer emplacement to insertion.
  • Declare functions noexcept whenever possible.
  • Make const member functions thread-safe.
  • Avoid std::enable_if in function signatures.
  • Handle iterators where copying means moving.

Rvalue References, Move Semantics, and Perfect Forwarding

  • Distinguish universal references from rvalue references.
  • Avoid overloading on universal references.
  • Pass and return rvalue references via std::move, universal references via std::forward.
  • Assume that move operations are not present, not cheap, and not used.
  • Be aware of perfect forwarding failure cases. 
  • Understand reference collapsing.

Secrets of the C++11 Threading API

  • Thread construction may throw.
  • Destroying a joinable thread calls terminate.
  • Arguments passed to std::thread, std::async, and std::call_once are unconditionally copied.
  • std::async is really two different functions with somewhat different APIs.
  • Futures from std::async are special.
  • void futures can be used for interthread communication.
  • To poll a future, use wait_for with a zero timeout.
  • Native handles let you go beyond the C++11 API.
  • Clock adjustments affect _until functions.

Lambda Expressions

  • Prefer lambdas to std::bind.
  • Prefer lambdas to variadic arguments for threading functions
  • Beware default captures in member functions.

Smart Pointers

  • Use std::make_shared whenever possible.
  • Prefer pass-by-ref-to-const to pass-by-value for std::shared_ptrs.

Miscellaneous

  • Pass by value when you’ll copy your parameter.
  • Keep abreast of standardization developments.
The number of Items on this list, the wording they have, the order in which they will occur, and whether they will ultimately be present are not just subject to change, they will change. This is especially true for the material pertaining to the threading API, because those "Items" are still just observations. But that's what my draft TOC looks like right now.

I also have a set of candidate guidelines that I currently feel are less important and hence less likely to make the book. This list will also change over time, but for your voyeuristic pleasure, this is what it contains:
  • Prefer non-member begin/end to member versions.
  • Declare std::thread and std::future members last.
  • For copyable types, view move as an optimization of copy.
  • Understand decltype.
  • Use std::compare_exchange_weak in loops.
If you have comments regarding any of the potential guidelines above, or if you have suggestions about what's not above but you believe should be, feel free to let me know, either as comments on the blog or via email: smeyers@aristeia.com.

"How much of this book have you written?," you may be wondering. None. Not a word. Zero percent. I haven't started writing, in part because I've allowed myself to get distracted by things like, um, creating blog entries...

But wording is everything. If you change the question to "How much of the work required to write this book have you already done?," the answer changes.  When I announced the existence of my annotated training materials for C++11, I explained that my approach to writing a book consists of three steps:
  1. Master the material.
  2. Figure out what "story" I want to tell, i.e., what to cover, what to omit, what order to cover things in, what examples to use, etc.
  3. Write it up.
I went on to break step 2 down as follows:
  • 2a: Come up with a story that I think will work, i.e., that will effectively convey the technical information.
  • 2b: Develop a training course corresponding to that story.
  • 2c: Deliver the training course to professional developers and see how well the story works. In places where it doesn't work as well as it should, return to step 2a and iterate until everything is satisfactory.
 For EC++11, I've pretty much completed steps 1 and 2, so from that perspective, I'm two-thirds done with the book :-) In theory, I know what I need to say. I just need to write it down. In reality, that understates the difficulty of the work that's still to be done, but to some degree, what remains is an IO-bound operation.

I would hope it goes without saying that you can't have too many iterations of steps 2a-2b-2c. Every time I present the material, I learn things about how I can do a better job. Sometimes it's about something I've said that was confusing or unnecessary. Sometimes it's about something I didn't say, but should have. Sometimes it's about a relationship between what I'm discussing and another topic that seemed completely independent to me, but didn't to the people I was working with. To that end, I'll be making several presentations of a new training course called Effective C++11 Programming several times this year. The first is slated to take place in June. I'll post details soon.

For the next few months, I'm doing my best to keep my calendar free. I need time to write Effective C++11. You know how slow IO-bound operations can be.

Scott

Effective C++11: Background

I've mentioned in some earlier posts that I plan to start writing a new book, Effective C++11.  The purpose of this post is to tell you a little bit about it. Lest there be confusion, let me emphasize that there is no book yet. If everything falls into place the way I hope it will, there will be a book about 10 months from now. If. I'm not making any promises.

If you're looking for information on the content of Effective C+11, this is the wrong place to seek it. I had originally planned to include a content summary, but once I'd written the background information that follows, I realized that the post was already too long. So the content information will go in a separate post.


People have been asking me to write Effective C++11 since before it would have been possible to give it that title. I started getting requests when the new version of the language, then known as C++0x, was still under development. I had a ready reply for such requests, aside from my considerable reluctance to write a book about a language that was still in flux. (Poor Anthony Williams' C++ Concurrency in Action remained in publishing purgatory for nearly three years, because he had the misfortune to publish an "early access" digital draft two years before the C++ Standard it corresponded to settled down. As a result, he had to keep revising the draft as updates to the emerging Standard were made, and that cannot have been fun. The result was worth both his effort and our patience, because the book is excellent. I strongly encourage you to consider buying it. I have. But I'm really glad I didn't have to go through the ordeal of writing it.)

My ready reply to requests to whip out Effective C++Whatever was that it's not possible to describe how to use a technology effectively until the community has enough experience with the technology to know what truly works and what doesn't. We'd all like to skip over experiencing the disappointment of what seem like great ideas that fail to pan out. We'd like to instantly come up with the nifty applications of features in ways nobody had foreseen. That'd be great. But as far as I know, the only way to separate the effective uses of C++11 from the ineffective ones is to try as many things as we can, then see what ends up in which pile. That takes time.

In truth, most people didn't ask for Effective C++Whatever. They asked for a new edition of Effective C++. It was the obvious thing to ask for, and it was the obvious thing for me to write, but it presented me with a problem I didn't know how to overcome.

The problem was (and is) that I constrain myself to books with no more than 300 pages. There is some wiggle room in that constraint, because I don't count front matter (preface and tables of contents, etc.--generally stuff numbered using Roman numerals), and if I had to, I'd probably be willing to ignore pages comprising the index. Nevertheless, my goal is to avoid producing a book with a page number higher than 300. The current edition of Effective C++ (available at fine bookstores everywhere, not to mention at a variety of illegal download sites, sigh) has, if you ignore the appendices and the index, a maximum page number of 272. That doesn't leave a lot of room for new material. And, as I've blogged about elsewhere, the material that's currently in the book remains largely valid under C++11. I didn't want to jettison a lot of useful material that's as valid under C++11 as under C++98, but I'm serious about the advantages of comparatively short books, so I didn't want to exceed the 300-page barrier, either.

The page limit problem held me back at least as much as the lack-of-experience problem. I knew that time would address the experience issue, but 300 pages wasn't going to get any bigger, no matter how long I waited. (Yes, I think like a programmer, so I couldn't help but toy with the ideas of playing games with smaller font sizes, narrower margins, page numbering using bases other than 10, and eliminating page numbers entirely. But cheating's less fun when the rules you're evading are the ones you made up in the first place.)

Last year, I experienced the proverbial brainsquall, and I realized that if most of Effective C++ remains valid under C++11, the solution is to not write a new edition of that book, but to write a new book. A book devoted to making effective use of the features unique to C++11. A book to complement Effective C++. That's my plan for Effective C++11:  to write a book describing how to make effective use of the features and capabilities in C++11 that are not present in C++98. A book with content entirely separate from my other C++ books and also largely separate from the content of my C++11 Overview Materials. In other words, all new stuff.  New from me, anyway.

The page constraint was thus vanquished, and experience with C++11 was slowly piling up on the information superhighway, but I had another concern. When I wrote my other books, I knew how they'd be published: as one or two colors of ink on more or less white paper of a fixed size. But the future of publishing was clearly digital, and I didn't know what it meant to produce a manuscript that should ultimately look good and be useful as both ink on paper and pixels on a screen, especially when some screens were monochrome (e.g., Kindle), and screen sizes varied from those of smart phones to those of UHDTV-capable monitors. During 2008-2010, I spent some time agonizing over this issue in my blog for Fastware!, a book that never came to be. I even gave a talk at a publishing conference about my concerns.

To be honest, I'm still not sure how to approach writing a manuscript when the result is to be published on multiple platforms, but analysis paralysis loses its appeal after a while, so I finally decided that if I don't know what the right way is, I might as well take a guess and see what happens. Exactly what that will mean in practice, I'm not sure, but my current plan is to write using Microsoft Word using lots of styles, and my assumption is that whatever manuscript format looks to be "right" when I have a manuscript ready to go, somebody will be able to figure out how to translate what I have in Word into that format.

Okay, having slogged through my whining about lack of experience, page limits, and manuscript preparation, you'd like to think I'll finally do something with a payoff for you. Something like offer some details about what will be in the book.  That I will. In my next post, which I plan to start writing immediately after publishing this one. Stay tuned.

Scott

Wednesday, January 23, 2013

Effective Effective Books

For the cover of the first edition of
Effective C++, I envisioned Alexander
the Great cutting the Gordian Knot.
I'm getting ready to start work on Effective C++11 (about which I'll have more to say in a later blog post), and this week I've been reviewing a manuscript for a new book in my Effective Software Development Series, so recently I've been thinking a lot about what makes an effective Effective book.

Effective books consist of a collection of technical essays ("Items"), where each essay's title comprises advice you should follow, and each essay's body consists of a rationale for the advice. In the third edition of Effective C++, for example, Item 37 is "Never redefine a function's inherited default parameter value."

This format has always seemed pretty straightforward to me, but having reviewed dozens of proposals and manuscripts for my series, it's clear that it's not straightforward to everybody. A few years ago, I wrote up the following guidelines for authors of prospective Effective books. Partly to remind myself of my own advice as I embark on a new book, and partly to have a place to point people who express interest in writing a book for my series, I thought I'd publish my guidance here.

Item 1: Keep Items short.

One of the things readers like best about Effective C++ is the brevity of the Items.  They're generally only 4-5 pages long, and that means that one can be read while waiting for a meeting to begin, during a quick break, even while using the bathroom.  I discovered this when I came out with my second book (More Effective C++), in which some items run for 10-20 pages.  Big mistake!  People want bite-sized chunks of useful information from an Effective book.  Give it to them.

Frankly, the constraint that Items be short is good for you as an author, because it forces you to think hard about what really needs to be included and what can be omitted (see below).  Also, it allows you to produce a book of typically under 300 pages, and a book of that length is something you've got half a chance of keeping in your head all at once.

Regarding overall book length, there are two ways to approach the matter.  It's a lot like packing for a trip.  You can either:
  • Choose all the stuff that you think you need, then find a big enough suitcase to hold it all, or
  • Choose the suitcase first, prioritize everything, then put in as many high-priority items as will fit.  
Effective books generally follow the latter strategy.

Think about your goals for your book.  Is it to tell your readers everything they need to know, or is it to tell them the most important things?  Remember that the longer your book, the less likely your readers will read all of it.  So what would you rather have?  A 250 page book that almost all readers read almost all of or a 500 page book that most readers read about half of?

It's your book, of course, and it's most important that you be happy with it, but you might bear in mind that I've published 140 Items on C++ programming spread across about 800 pages, but I did it in 3 different books.  I think my readers like it better that way, because there's less for them to digest at one time.  I know I like it better the way I did it, because I find it a lot easier to keep no more than 300 pages of material straight than to try to wrestle with 800 pages at once.  Also, I like knowing that my readers are likely to read each book all the way through.  I hate it when I work hard at writing something, only to find that some people stopped reading before they got to the end.  I have a story I want to tell them, and it's important to me that they get the entire story.

If you have a lot to say, there's no law that says you have to say it in a single book. Splitting it across multiple books may end up serving everybody better.

Bear in mind that Effective books are designed to be "the standard second book" on their topic.  You should assume that readers know the basics and have another comprehensive reference available to them.

Item 2: Put Item titles in the imperative.

People read Effective books for advice, to learn "the things the experts almost always do--or almost always avoid doing."  They want to be told what to do or what not to do, so each item should give them an order: Do this or don't do that (ideally the former--see below).  Statements are not as helpful as imperatives, so don't use statements as Item titles.

As an example, I could have worded this Item as "Imperative Item titles are good," but that's not advice, it's just a statement.  "Put Item titles in the imperative" is advice.  Your readers want advice.  Provide it.

Alas, they sometimes want advice when what they really need is information.  Fortunately, there's a way to give them both: use imperatives that begin with "Understand" or "Familiarize yourself with" or "Be aware of" or things of that ilk.  For example, if you think that people generally fail to grasp the subtleties of some topic XYZ and you feel that they really need to understand it in order to be effective software developers, consider a title like, "Familiarize yourself with the subtlties of XYZ."  It's still an imperative.

After reading your book, people will want a convenient summary of the advice it contains.  If each Item title is an imperative, the book's TOC (Table of Contents) will be a summary of its advice, and that should be one of your goals: to have the TOC summarize the advice in the book.

Item 3: Make Item advice as specific as possible.

The best advice is so specific, it can be checked by a machine.  In fact, many of the guidelines I put in Effective C++ have been incorporated into static analysis tools.  Specific advice is also good for code reviews, because it eliminates the interpretation factor; readers don't argue over what a particular Item means.  They might argue over whether a particular Item is justified (see below), but if the advice is specific, they won't argue over what it means.

If you are having trouble making a guideline specific, it could be because the topic you are writing about in that Item is too general.  If that's the case, perhaps you need to break it down into two or more separate (and more specific) guidelines.  For example, if you're trying to offer advice about the proper use of inheritance, but you find that it's hard to be specific, because interface and implementation inheritance are so different, consider writing two items, one about interface inheritance, the other about implementation inheritance.

Item 4: Word Item titles carefully.

Your TOC summarizes your book's advice.  Furthermore, your TOC consists primarily of your Item titles.  That means that the most important sentences in your book are the ones making up your Item titles.  All words in a book are worth agonizing over, but some are more agonizable than others, and the ones in your Item titles are the most agonizable of all.  They make up the advice you want your readers to remember, even if they forget everything else in the book.  As a result, you want your Item titles to (1) be easy to remember and (2) accurately summarize your advice on the topic addressed by the Item.

Resist the urge to choose titles that are catchy, but not informative.  One manuscript I read had an item on using profilers to guide optimization efforts, and the Item title was "Optimize optimally."  This is catchy, but it doesn't summarize the advice in the Item.  Item titles are different from article titles.  Authors often choose enigmatic article titles to intrigue people into reading the article.  That's not the goal in an Effective Item.  Readers already have the book. You can expect them to read it.  The goal of an Item title is to summarize in a few words the advice that will take several pages to justify.  Remember: the Item title is "what."  The Item body is "why."

When I write my books, I typically revise the wording of Items several times.  I'll start with what I think I want to say, but after I've written an Item's body, I'll realize that my justification doesn't really back the title, so I'll revise the title.  Or after I've written other Items, I'll discover that some of what what I wanted to say in Item n is now in Item m, so I'll go back and revise Item n's title to reflect the fact that it no longer addresses the concerns of Item m.

Any time my Item title is too long to fit on a single line, I'll try to come up with a shorter way to say it.  Short Item titles are easier to remember than longer ones, and my goal is for my readers to remember all the titles of all the Items.  The easier I make it for them to do that, the better my odds of achieving my goal.

You'll note that several of the other Items in this document relate to Item wordings.  That's no accident.  It's a reflection of the importance of Item titles to Effective books.  You've got just a few words to summarize the lessons of several pages of often complex material.  Choose them carefully.  They're the most important words in your book.

Item 5: Prefer guidelines that say what to do over what not to do.

Guidelines that tell people what they should do are more useful than guidelines that tell them what they should not do.  If a programmer wants to accomplish task X, knowing that they should not do A, B, or C may narrow the design space, but it doesn't really tell them how to accomplish X.  Any time you are tempted to start an item with "Avoid" or "Never", imagine the following conversation with your readers:
       You:         Avoid doing A.
       Readers:   But if I don't do A, how can I accomplish X?
       You:         Do B instead.

If you can come up with such a conversation, you probably want to word your Item as something like "Prefer B to A for X."  (See below for more information on words like "avoid" and "prefer" in Item titles.)

Item 6: Tell the truth and nothing but the truth, but not necessarily the whole truth.

Effective books are short by design, typically only about 5 pages per Item.  With such limited space, it's important to include only information readers really need to know.  Your goal should be to help your readers, not to demonstrate your mastery of history or trivia, etc.  After all, one of the things they are paying you for is deciding what they don't need to know.

At the same time, you lose your credibility if you lie to your readers, so you must never lie.  To avoid lying while also shielding them from information they don't need to know, you will need to fall back on weasel words: typically, generally, usually, etc.  You don't want to use these more than you have to, because readers will notice them, but if your choices are a two-page digression on how some bizarre machine or compiler that almost nobody uses does something in a strange way or slipping "virtually" in front of "all implementations," then "virtually" and its kin are your friends.

Item 7: Back Items with solid technical arguments.

The most common weakness I see in prospective Effective books is that the Item rationales fail to make convincing cases for the Items' advice.  This is critical!  Remember, you're telling somebody what to do.  You're probably asking them to change the way they do things.  If they're going to change their habits, and especially if they're going to let you push them around, they'll demand a good reason, and it's your job to give it to them.  You should assume that your readership is smart, experienced, and critical.  Effective books aren't introductory, so your readers already know some of what you're talking about.  Some of it they know as well as you do.  If you tell people to do X, but fail to acknowledge that it's impractical some of the time, they'll notice, and you'll lose credibility.  If you tell them that they have to do X because of Y, but Y isn't true, they'll notice, and again, you'll lose credibility.  You can't afford to lose credibility, because if you're not credible, why should
your readers take your advice?

In addition, there are almost certainly going to be exceptions to any advice you can offer, and one of the most important things you must do as an author is explain to your readers when your advice applies and when it does not.  The Item rationale is the place where you do that, at least implicitly.  For example, I spend a lot of time in my C++ books talking about how to prevent resource leaks, and much of my advice boils down to, "Do this, because it helps prevent resource leaks."  At one point, I was talking to engineers who work on the software that runs inside missiles.  Their programs run until the missile hits its target.  They don't care about leaking resources at program shutdown, because their programs never shut down.  They stop running only when the bomb goes boom.  As a result, they feel free to ignore some of my advice, and that's perfectly reasonable.  But the only way they know that that is perfectly reasonable is because my books make clear the technical motivation for the advice I give.  When that motivation fails to apply, so does the advice.

Item 8: End each Item with a summary of its advice.

The old saw is "Tell 'em what you're going to tell 'em; tell 'em; tell 'em what you told 'em."  Effective Items are similar, but not quite the same: Tell them what they need to remember; justify it; remind them of what they need to remember.

If you've worded your Items correctly (see above) what they need to remember is the Item title, a single sentence of only a few words.  The justification typically runs 4-5 pages, and that's where you deal with implementation strategies, portability issues, exceptions to the rules, explanations of why things are the way they are, etc.  By the time you're done with that, there is every likelihood that your readers have forgotten the main point you initially set out to make.  You therefore need to remind them.  It doesn't need to be long-winded; a sentence, short paragraph, or set of bullet points is all you need.  For example, for an Item with this title,
  Write operator delete if you write operator new.
I end this way (9 pages later, sigh):
Now, it's interesting to see how custom memory management routines can improve program performance, and it's worthwhile to see how such routines can be encapsulated inside a class like Pool, but let us not lose sight of the main point. That point is that operator new and operator delete need to work together, so if you write operator new, be sure to write operator delete, as well.
For the third edition of Effective C++, I added a short list of bullet points to the end of each Item called "Things to Remember." That allowed me to eliminate the summary paragraphs from many Items while still allowing me to remind readers of each Item's most important information.

Item 9: Know how to modulate the stridency of Item titles.

Virtually every rule has exceptions, but some rules have more exceptions than others.  The wording of your Item titles should reflect the likelihood that your readers will encounter exceptions.  In real life, for example, we should (almost) always buckle up for safety, (almost) never drink and drive, and (typically) consider taking public transit when it is available.  Those three words--always, never, and consider--are three of the five words I've found useful when wording Item titles.  Here's the full scale of advice urgency, from Always to Never:
  •   Always
  •   Prefer
  •   Consider
  •   Avoid
  •   Never
The default is "Always," so it's generally implicit.  I could have worded one of the guidelines above  this way, for example,
Always put Item titles in the imperative.
but "Always" here adds little, so there's no point in including it. 

Because every rule has exceptions, there's an implicit "Almost" in front of any rule that begins with "Always" or "Never." However, including "Almost" in Item titles draws attention to the existence of the exceptions, and that's not what we want readers to focus on.  For example, consider how wishy-washy this looks:
Almost always put Item titles in the imperative.
Please!  Take a stand!  That's one of the things that readers like about Effective books: the authors give specific advice instead of bland platitudes.  Each Item has a rationale,  so any situation not covered by the rationale can naturally be interpreted as being an exception to the rule.  Hence the implicit nature of "Almost."

Item 10: Cross reference liberally.

Effective books are collections of essays.  Each is specific and constrained (see above), but collectively they cover a lot of territory.  The territories they cover necessarily abut and overlap, and that means that almost no Item stands alone.  When there are relationships among Items, readers need to know that.  That's where Item cross-referencs come in.  If Item A gives a detailed discussion of a topic that's relevant to Item B, B should probably have a cross-reference to A.  (A might also have a cross-reference to B.)  If Item A strengthens the rationale for Item B, B should probably have a reference to A.  If Items A and B cover disjunctive situations, both should probably refer to one another (e.g., "Item A explains why you need to do X to achieve Y, but sometimes your goal isn't Y, it's Z.  When that's the case, the advice in Item A fails to apply...").

In the end, most everything is related to everything else in some way or another.  You don't need to point out all relationships to your readers (see above about omitting information they don't need to know), but you should definitely use cross references to point out the ones that are important in making effective use of whatever technology you are writing about.

Item 11: Minimize use of footnotes.

Footnotes make a book look more formal and academic.  Effective books tend to shoot for a more casual, informal approach.  As a result, it's best to avoid footnotes whenever possible.  In general, you'll find that information you want to footnote can either be eliminated or incorporated into the body of your discussion.

Item 12: Be consistent when referring to yourself and your readers.

This is a grammatical "person" issue: first person, second person, or third person?  When you refer to the author of the book, do you say "I" (first person) or "the author" (third person)?  When you refer to the reader of the book, do you say "you" (second person) or "the reader" (third person)?  The choices are nowhere near as important as that you abide by them consistently.  I like to envision Effective books as one-on-one informal conversations between the author(s) and each reader, so I prefer using first person for the author and second person for the reader, e.g., "Now, when I say that XYZ is a good idea, I suspect you'll wonder if I'm off my rocker."  Third person works, too, though I think it's stuffy: "When considering the author's recommendation to do XYZ, the reader may be forgiven for wondering if the author is off his rocker."

Bottom line: I see too many manuscripts where authors can't decide how to refer to themselves or their readers.  Make the decision early on, write it down so you remember it, and adhere to it consistently.

Item 13: Seek out ruthless pre-publication reviewers.

No matter how careful you are, odds are that the book you write will contain errors or other problems.  That being the case, it's in everybody's interest to find out about them as soon as possible.  Ideally, you'll find out about them before the book is actually published, thus giving you a chance to fix them before your masterpiece is loosed on the world.

There are many ways to get good pre-pub feedback, but all have one thing in common: they are based on finding reviewers who are willing and able to tell you how your book can be improved and who don't pull punches.  What you want to hear is that your manuscript is wonderful and is ready for publication, but what you need to hear is that some words are misspelled, some diagrams are confusing, some topics are technically incorrect, the way you've organized things makes no sense, and that you've failed to consider some aspects of the material that are important.

Providing such feedback is hard work, and that means that you're unlikely to find people willing to give it to you unless you go looking for them.  Seek them out.  Tell them you want to know everything that is wrong with your manuscript.  Make it clear that a better book is more important to you than an unbruised ego.  Ask your friends to be reviewers only if (1) you believe they are willing to be brutal in their comments and (2) you honestly believe that your friendship can withstand the pressure.  But don't rely only on your friends.  Seek out individuals who are representative of your target audience, and ask them to tell you what they think.  (Your friends are unlikely to be good at this.  For one thing, there's a very good chance that your friends know more about what you're writing about than your average target readers does.  After all, your friends hang out with you.  Your readers don't.)

When I circulated an early draft of my second book, I got back comments from one reviewer who, having savaged the first 30-40 pages, concluded with "It doesn't get any better after that."  It took me a couple of days to recover from that, but once I did, I was able to dispassionately evaluate the comments and conclude that they were accurate.  Then I rewrote the book, making extensive revisions.  The resulting book was much better than it would have been had I received only comments telling me that this or that detail needed tweaking.

It's nice to hear nice things about what you've written.  You're much more likely to hear them after your book comes out if you've heard awful things when the book is in progress.  Seek out people who will tell you those awful things in advance so you won't have to hear them later.