<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>A rant against flow control macros</title><link>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/06/347666.aspx</link><description>It may be easier for you, but it makes it harder for everyone else.</description><dc:language>en-US</dc:language><generator>Telligent Evolution Platform Developer Build (Build: 5.6.50428.7875)</generator><item><title>???????????? (2007-07-09)   [JeffHung.Blog]</title><link>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/06/347666.aspx#3782787</link><pubDate>Mon, 09 Jul 2007 18:46:13 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3782787</guid><dc:creator>???????????? (2007-07-09)   [JeffHung.Blog]</dc:creator><description>&lt;p&gt;PingBack from &lt;a rel="nofollow" target="_new" href="http://www.jeffhung.net/blog/articles/jeffhung/952/"&gt;http://www.jeffhung.net/blog/articles/jeffhung/952/&lt;/a&gt;&lt;/p&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=3782787" width="1" height="1"&gt;</description></item><item><title>QQ by omerm () | LjSEEK.COM</title><link>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/06/347666.aspx#1350656</link><pubDate>Sat, 23 Dec 2006 05:58:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1350656</guid><dc:creator>QQ by omerm () | LjSEEK.COM</dc:creator><description>&lt;p&gt;PingBack from &lt;a rel="nofollow" target="_new" href="http://www.ljseek.com/qq_52954724.html"&gt;http://www.ljseek.com/qq_52954724.html&lt;/a&gt;&lt;/p&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1350656" width="1" height="1"&gt;</description></item><item><title>omerm: QQ</title><link>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/06/347666.aspx#1350655</link><pubDate>Sat, 23 Dec 2006 05:57:58 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1350655</guid><dc:creator>omerm: QQ</dc:creator><description>&lt;p&gt;PingBack from &lt;a rel="nofollow" target="_new" href="http://www.livejournal.com/users/omerm/55178.html"&gt;http://www.livejournal.com/users/omerm/55178.html&lt;/a&gt;&lt;/p&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1350655" width="1" height="1"&gt;</description></item><item><title>Engineering Technology  &amp;raquo; Blog Archive   &amp;raquo; Macros are bad.</title><link>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/06/347666.aspx#577698</link><pubDate>Mon, 17 Apr 2006 21:39:59 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:577698</guid><dc:creator>Engineering Technology  » Blog Archive   » Macros are bad.</dc:creator><description>PingBack from &lt;a rel="nofollow" target="_new" href="http://engtech.wordpress.com/2006/04/14/w-cc-macros-are-bad/"&gt;http://engtech.wordpress.com/2006/04/14/w-cc-macros-are-bad/&lt;/a&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=577698" width="1" height="1"&gt;</description></item><item><title>re: A rant against flow control macros</title><link>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/06/347666.aspx#350616</link><pubDate>Tue, 11 Jan 2005 14:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:350616</guid><dc:creator>Purplet</dc:creator><description>quote :&lt;br&gt;Macros are great. My only complaint against them is that nobody has added an extension to swallow up the first { or ; token that comes after the usage of the macro.&lt;br&gt;&lt;br&gt;&lt;br&gt;#define SOMETHING(A) do { something(A); } while(0)&lt;br&gt;&lt;br&gt;it swallows the ; and works ok if used in loops, ifs, etc :)&lt;br&gt;&lt;br&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=350616" width="1" height="1"&gt;</description></item><item><title>re: A rant against flow control macros</title><link>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/06/347666.aspx#350582</link><pubDate>Tue, 11 Jan 2005 13:20:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:350582</guid><dc:creator>Paul Spendlove</dc:creator><description>Michael Greer:&lt;br&gt;&amp;quot;C++ is very useful over C without dragging exceptions into the mix. Exceptions are an experiment which has gone awry. They're the new snake oil. They work well in functional languages since there aren't side effects to be rolled back. Even people who believe in RAII are rarely actually prepared to make every possible error control path actually have all the rollback necessary.&amp;quot;&lt;br&gt;&lt;br&gt;Michael, why not read Bjarne Stroustrup's &amp;quot;Appendix E&amp;quot; to the &amp;quot;C++ Programming Language (3rd ed)&amp;quot;? It puts forward the views of the designer of the language on exception safety. It has been freely available on the web for more than 4 years by now. &lt;br&gt;&lt;br&gt;I think it's something you haven't read yet. Why? Because you refer to RAII taking effort to implement and involving &amp;quot;rollback&amp;quot;. But RAII is actually quite easy to implement and has *nothing* to do with whether you offer rollback semantics.&lt;br&gt;&lt;br&gt;As well as defining what RAII actually means in this document, Stroustrup also points out why exceptions were added to C++ - to deal with errors in object construction. There are alternative ways to deal with such errors (eg by providing a separate error-checked &amp;quot;init()&amp;quot; function). Stroustrup covers the alternatives, and explains why he finds exceptions superior. I find his arguments convincing. You are at liberty to differ, but it's surely worth at least checking out what Stroustrup has to say.&lt;br&gt;&lt;br&gt;RAII is really not hard to do. It generally requires no more than a good reference-counted templated pointer - such classes are widely and freely available, eg from the boost project. You frequently don't need to roll back every single operation, you just need to recover back to some higher level. Generally, simply releasing resources on the way back up the call chain is completely sufficient. When you *do* need to group stuff together in a transaction, you create a transaction object whose destructor rolls back, and give it a scope surrounding the members of the transaction.&lt;br&gt;&lt;br&gt;In conclusion, if people wish not to use C++ exceptions, it's up to them. But if they are going to talk about exceptions in C++ and use terms such as RAII, they'll be able to make their points more convincingly if they first read what the designer of the language has to say on the topic. &lt;br&gt;&lt;br&gt;PS RAII = &amp;quot;Resource Acquisition Is Initialisation&amp;quot;, for those who were wondering.&lt;br&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=350582" width="1" height="1"&gt;</description></item><item><title>re: A rant against flow control macros</title><link>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/06/347666.aspx#350301</link><pubDate>Tue, 11 Jan 2005 02:11:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:350301</guid><dc:creator>Memet</dc:creator><description> Micheal: I agree that hidden control flow is evil, but I also think cleanup code shouldn't be 'cleanup' code at all.&lt;br&gt; I think we would all agree that duplicate code is the worst evil of all, correct? Well, in an ideal OO world where initialization is aquisition (with all the corrollaries that apply), there should never be 'cleanup code'. In my opinion, cleanup code can _never_ not be duplicate code. Anything that goes out of scope should 'internally' do all operations it requires to free its resources (ie. execute its destructor). That has the advantage of localizing functionality. That also has the advantage of providing a language-wise transactional environment where I should not need to know what all possible exit paths are because the owners of the resources clean themselves up.&lt;br&gt;&lt;br&gt; My favorite example of what I hate is creating an ATL ASP object using the wizard. This is the code that gets generated:&lt;br&gt;hr = lpContext-&amp;gt;get_Request(&amp;amp;lpRequest);&lt;br&gt;if(FAILED(hr))&lt;br&gt;{	lpContext.Release();&lt;br&gt;	return hr;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// Get Response Object Pointer&lt;br&gt;hr = lpContext-&amp;gt;get_Response(&amp;amp;lpResponse);&lt;br&gt;if(FAILED(hr))&lt;br&gt;{	lpContext.Release();&lt;br&gt;	lpRequest.Release();&lt;br&gt;	return hr;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// Get Server Object Pointer&lt;br&gt;hr = lpContext-&amp;gt;get_Server(&amp;amp;lpServer);&lt;br&gt;if(FAILED(hr))&lt;br&gt;{	lpContext.Release();&lt;br&gt;	lpRequest.Release();&lt;br&gt;	lpResponse.Release();&lt;br&gt;	return hr;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// Get Application Object Pointer&lt;br&gt;hr = lpContext-&amp;gt;get_Application(&amp;amp;lpApplication);&lt;br&gt;if(FAILED(hr))&lt;br&gt;{	lpContext.Release();&lt;br&gt;	lpRequest.Release();&lt;br&gt;	lpResponse.Release();&lt;br&gt;	lpServer.Release();&lt;br&gt;	return hr;&lt;br&gt;}// ad infinitum&lt;br&gt;&lt;br&gt;Aside from the fact that the wizard generates object code but still uses functional cleanup (which I find weird), you can't seriously be advocating that this (cleanup as required) is good practice, can you?&lt;br&gt; With exceptions, and a properly OO model, hidden control flow becomes irrelevant as you don't need clean up anyways. It's only when you mix and match API and OOP that it becomes tricky, but that brings me back to my original post's point.&lt;br&gt;&lt;br&gt; All in all though, I don't mean to drag you into a flame war about OOP and exceptions. My point is just that I personally find that C++ doesn't really help you or provide you with tools for dealing with method encapsulation in a way that avoids code duplication, and that was originally why I had said Macros were useful for.&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=350301" width="1" height="1"&gt;</description></item><item><title>re: A rant against flow control macros</title><link>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/06/347666.aspx#349802</link><pubDate>Mon, 10 Jan 2005 10:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:349802</guid><dc:creator>AC</dc:creator><description>&lt;br&gt;Michael Grier: I don't consider your IF_FAILED_GOTO_EXIT as a good practice. I guess you've debugged a lot of deep nested ifs, but that's also bad practice. Good code shouldn't be too nested. If you introduce some coding discipline, you can always do something like&lt;br&gt;&lt;br&gt;void DoSomething( ...&lt;br&gt; if ( cond1 ) return;&lt;br&gt; someth1();&lt;br&gt; if ( cond2 ) return;&lt;br&gt; mainThing&lt;br&gt;&lt;br&gt;etc. Instead the above code some people would produce two nested ifs, and when the &amp;quot;main thing&amp;quot; has any logic, there are more nestings, and the code is hard to follow. Making &amp;quot;early returns&amp;quot; has also good effect of looking (to me) more like mathematical expression where you first exclude trivial cases.&lt;br&gt;&lt;br&gt;Very often, when I get the code from somebody else, and rewrite the &amp;quot;multiple nesting&amp;quot; to the above presented principle (anybody knows if there's some name for it) I easily discover that the original author didn't cover some cases. Multiple ifs make it hard to see uncovered cases. Using a lot of returns stimulates covering all the cases.&lt;br&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=349802" width="1" height="1"&gt;</description></item><item><title>re: A rant against flow control macros</title><link>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/06/347666.aspx#349695</link><pubDate>Mon, 10 Jan 2005 05:59:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:349695</guid><dc:creator>Michael Grier [MSFT]</dc:creator><description>Re: memet:&lt;br&gt;&lt;br&gt;C++ is very useful over C without dragging exceptions into the mix.  Exceptions are an experiment which has gone awry.  They're the new snake oil.  They work well in functional languages since there aren't side effects to be rolled back.  Even people who believe in RAII are rarely actually prepared to make every possible error control path actually have all the rollback necessary.&lt;br&gt;&lt;br&gt;The point of the other blog entry Raymond references is that:&lt;br&gt;&lt;br&gt;a = b + c;&lt;br&gt;&lt;br&gt;doesn't clearly have any control flow when in fact it may have 3 (or 2 more if you consider failures in destructors for temporaries which terminate the application to be control flow).&lt;br&gt;&lt;br&gt;MUST_SUCCEED(Foo());&lt;br&gt;&lt;br&gt;is not better.  There's some statement of intent but it's not clear what the ramifications are.  But then I've also seen this style:&lt;br&gt;&lt;br&gt;check &amp;lt;&amp;lt; Foo();&lt;br&gt;check &amp;lt;&amp;lt; Bar();&lt;br&gt;&lt;br&gt;is that clear either?  No, and for the same reason.  I forget where I saw this but the rationale given by the team was that it's an idiom used in their source and when you get used to it, it's clear.&lt;br&gt;&lt;br&gt;My point here at the end is that this actually has nothing to do with the use of macros.  Hidden control flow is bad.  It causes a lot of errors.&lt;br&gt;&lt;br&gt;If we can agree that all of:&lt;br&gt;&lt;br&gt;if (FAILED(hr = Foo()) goto Exit;&lt;br&gt;if (FAILED(hr = Bar()) goto EXit;&lt;br&gt;&lt;br&gt;and&lt;br&gt;&lt;br&gt;if (SUCCEEDED(hr = Foo())) {&lt;br&gt;   hr = Bar();&lt;br&gt;}&lt;br&gt;return hr;&lt;br&gt;&lt;br&gt;and&lt;br&gt;&lt;br&gt;IF_FAILED_GOTO_EXIT(Foo());&lt;br&gt;IF_FAILED_GOTO_EXIT(Bar());&lt;br&gt;&lt;br&gt;are reasonably clear (assuming that the macros do the expected thing... do you verify that SUCCEEDED() does what you expect?) then we can have a more interesting debate about:&lt;br&gt;&lt;br&gt;a. How important RAII is&lt;br&gt;b. When do you split functions vs. nest conditions&lt;br&gt;&lt;br&gt;I think that RAII is very important and I further think that if you can adopt a reasonable style you can prevent arbitrary new functions created only because the previous style created artificial source bloat and statement nesting.  I like the use of macros because except for the annoying extra text on each source line, you get control flow that looks very much like the &amp;quot;exception-based ideal&amp;quot;.&lt;br&gt;&lt;br&gt;(I alluded to this but on my team when we started a recent project, we didn't mandate use of the error checking macros.  So what happened?  A lot of little error-path-cleanup code snippets occurred which of course didn't get all the error paths covered.  Thus we decided to disallow the explicit checks and &amp;quot;goto Exit;&amp;quot;.)&lt;br&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=349695" width="1" height="1"&gt;</description></item><item><title>re: A rant against flow control macros</title><link>http://blogs.msdn.com/b/oldnewthing/archive/2005/01/06/347666.aspx#349035</link><pubDate>Sat, 08 Jan 2005 04:20:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:349035</guid><dc:creator>Memet</dc:creator><description>(Sigh, I just lost my entire post, I'm retyping)&lt;br&gt;&lt;br&gt;Kent Boogaart:&lt;br&gt; The reason why we've opted to use macros across the project is because we wanted a unified exception handling system.&lt;br&gt; What that means is that any exception thrown in a particular system should be a well known exception, preferably derived from a base class. So the macros handle either defined program failures, or catch all failures (which generally indicate there was a problem that we didn't account for - which is bad).&lt;br&gt; Also, exceptions aren't meant to be used as control flow logic, they are meant to interrupt normal flow because something serious has occured.&lt;br&gt; A good example is std::map::find() which returns std::map::end() if it can't find the required element, it does *not* raise an exception. So it is wrong to compare exceptions to code like this:&lt;br&gt;hr = SomeOperation();&lt;br&gt;if( FAILED( hr ) )&lt;br&gt; hr = DoSomeOtherOperation(); &lt;br&gt;else&lt;br&gt; hr = DoSomethingCool();&lt;br&gt;&lt;br&gt; Here, we have a clear case of flow control based on the outcome of some function. On the other hand, operations like 'new' need to be atomic from a syntactic perspective, and not raising an exception when a object fails instantiation is not an option.&lt;br&gt; In the same vein, in the project we're in, components do not raise exceptions when their output is not something that cannot be recovered from, but when it is they do. And at that point, having a unified exception handling architecture really gives cohesion to the system since now you can log what's happening in the app using, for example, a single point of logging in your base exception class.&lt;br&gt;&lt;br&gt; Michael Grier:&lt;br&gt; The problem is not that we are in a blissful state of denial, it's that C++ needs exceptions to be robust. C++ classes could not be instantiated properly without exceptions. When that observation sets in, you are faced with either using C++ as an enhanced C syntax compiler, and using COM (or something else) as your object model, or using C++ as an object oriented language and interfacing with COM as you would with any other C API. Even the #import code generates _com_error exceptions when wrapping around COM objects. It's just a matter of principle, and for those who want to use C++ as an OOP, then exceptions are the way to go.&lt;br&gt;&lt;br&gt;(I'm sure I forgot to say something from what I had originally written, ah well)&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=349035" width="1" height="1"&gt;</description></item></channel></rss>