<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Software EngiSneering</title><link>http://softwareengisneering.blogspot.com/</link><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/SoftwareEngisneering" /><description>Unix software development rants.</description><language>en</language><managingEditor>noreply@blogger.com (Bill Night)</managingEditor><lastBuildDate>Thu, 12 Jan 2012 20:03:40 PST</lastBuildDate><generator>Blogger</generator><atom:id xmlns:atom="http://www.w3.org/2005/Atom">tag:blogger.com,1999:blog-837664636726682837</atom:id><openSearch:totalResults xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">58</openSearch:totalResults><openSearch:startIndex xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">1</openSearch:startIndex><openSearch:itemsPerPage xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/SoftwareEngisneering" /><feedburner:info uri="softwareengisneering" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/SoftwareEngisneering" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2FSoftwareEngisneering" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><item><title>gcc error: invalid use of member (did you forget the `&amp;' ?)</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/6ARNbhPgHys/gcc-error-invalid-use-of-member-did-you.html</link><category>gcc</category><category>tips</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Thu, 12 Jan 2012 20:03:00 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-592415034886633040</guid><description>Every time I have gotten the above compilation error, it has nothing to do with a missing ampersand.  Instead, it is missing function-call parentheses:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;  if (you_go &amp;&amp; use-&gt;yourMember) { // WRONG!
    this-&gt;isInvalid();
  }

  if (i_go &amp;&amp; use-&gt;myMember()) { // Oh yeah, the parens.
    continue;
  }
&lt;/pre&gt;&lt;br /&gt;
So don't use your member invalidly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-592415034886633040?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=6ARNbhPgHys:t-59HNecRyw:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=6ARNbhPgHys:t-59HNecRyw:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=6ARNbhPgHys:t-59HNecRyw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=6ARNbhPgHys:t-59HNecRyw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=6ARNbhPgHys:t-59HNecRyw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/6ARNbhPgHys" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2012-01-12T20:03:40.519-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2012/01/gcc-error-invalid-use-of-member-did-you.html</feedburner:origLink></item><item><title>Don't Avoid No-ops</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/9ffUJf95CIE/dont-avoid-no-ops.html</link><category>case analysis</category><category>style</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Fri, 11 Mar 2011 16:39:00 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-8318084716450228114</guid><description>A form of &lt;a href="http://softwareengisneering.blogspot.com/2008/08/eschew-case-analysis.html"&gt;spurious case analysis&lt;/a&gt; that seems to come up a lot in the code I have to work on right now falls under the category of "avoiding a no-op".  Well, don't add cruft to your code just to avoid a no-op.&lt;br /&gt;
&lt;br /&gt;
Here's the one that I see hundreds of:&lt;br /&gt;
&lt;pre&gt;  if (ptr != NULL) {
    delete ptr;
  }
&lt;/pre&gt;Instead of:&lt;br /&gt;
&lt;pre&gt;  delete ptr;
&lt;/pre&gt;But the line that caused me to post this today was this:&lt;br /&gt;
&lt;pre&gt;  if (!isalnum(str[i]) &amp;&amp; (str[i] != '_')) str[i] = '_';
&lt;/pre&gt;Why complicate the if condition just to make sure and not overwrite an underscore with an underscore?  In reading through this code I paused to consider when an underscore could occur, and whether something special had to happen, only to read a little further and see that someone was guarding against a no-op.  Good lord, just perform the no-op so I can read this more easily:&lt;br /&gt;
&lt;pre&gt;  if (!isalnum(str[i])) str[i] = '_';
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-8318084716450228114?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=9ffUJf95CIE:Vn3PsdZf0Nw:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=9ffUJf95CIE:Vn3PsdZf0Nw:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=9ffUJf95CIE:Vn3PsdZf0Nw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=9ffUJf95CIE:Vn3PsdZf0Nw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=9ffUJf95CIE:Vn3PsdZf0Nw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/9ffUJf95CIE" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2011-03-11T16:39:33.032-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2011/03/dont-avoid-no-ops.html</feedburner:origLink></item><item><title>Filename Expansion in Tcl</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/-Tg8Ij5H-V8/filename-expansion-in-tcl.html</link><category>negative</category><category>tips</category><category>tcl</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Thu, 27 Jan 2011 17:05:00 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-1970365816764543762</guid><description>Stupid, stupid, Tcl.  If you want to run a shell command with a glob filename, like &lt;code&gt;*.h&lt;/code&gt;, you can't just do:&lt;br /&gt;
&lt;pre&gt;exec ls -l *.h
&lt;/pre&gt;&lt;br /&gt;
You have to explicitly tell Tcl to expand the glob, because it will pass *.h to the shell literally.  But you also can't do:&lt;br /&gt;
&lt;pre&gt;exec ls -l [glob *.h]
&lt;/pre&gt;&lt;br /&gt;
because it will pass the entire list to the shell literally (thanks, Tcl, that's useful).  You get lucky and it works if there is exactly one file matched by the glob.  Otherwise &lt;code&gt;ls&lt;/code&gt; will complain that there's no file called "a.h b.h c.h".&lt;br /&gt;
&lt;br /&gt;
So what do you do?  Unfortunately, if you pull up the man page for &lt;code&gt;exec&lt;/code&gt; on the internet, it tells you a way to do this that is only syntactically valid for Tcl 8.5 or greater.  For those of us living in the past, the demonic incantation you must utter is:&lt;br /&gt;
&lt;pre&gt;eval [list exec ls -l] [glob *.h]
&lt;/pre&gt;&lt;br /&gt;
Don't use Tcl unless you have to.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-1970365816764543762?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=-Tg8Ij5H-V8:Hw7uP0SUyGc:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=-Tg8Ij5H-V8:Hw7uP0SUyGc:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=-Tg8Ij5H-V8:Hw7uP0SUyGc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=-Tg8Ij5H-V8:Hw7uP0SUyGc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=-Tg8Ij5H-V8:Hw7uP0SUyGc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/-Tg8Ij5H-V8" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2011-04-22T09:46:20.477-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2011/01/filename-expansion-in-tcl.html</feedburner:origLink></item><item><title>C++ Static No Longer Deprecated</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/i7RsqGrBowI/c-static-no-longer-deprecated.html</link><category>c++</category><category>tips</category><category>style</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Wed, 26 Jan 2011 12:00:00 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-3019935944870201478</guid><description>Wow, a long-held piece of geek trivia is no longer true.&lt;br /&gt;&lt;br /&gt;This &lt;a href="http://stackoverflow.com/questions/4726570/deprecation-of-the-static-keyword-no-more"&gt;Stack Overflow article&lt;/a&gt; points out that in a recent draft of the upcoming &lt;a href="http://en.wikipedia.org/wiki/C%2B%2B0x"&gt;C++0x&lt;/a&gt; revision to the C++ standard, file-scope &lt;code&gt;static&lt;/code&gt; declarations are no longer deprecated.  For, oh, 20 years, it's been one of those finer language points that you can whip out to show your sophistication and look down on the ignorant.  But between the August 2010 draft &lt;a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3126.pdf"&gt;(pdf)&lt;/a&gt; and the November 2010 draft &lt;a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3225.pdf"&gt;(pdf)&lt;/a&gt;, the section deprecating &lt;code&gt;static&lt;/code&gt; has been struck!&lt;br /&gt;&lt;br /&gt;If you're unfamiliar with the issue, it's that anonymous &lt;code&gt;namespaces&lt;/code&gt; provide a more general solution to the multiply-defined symbol problem.  Instead of:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  static int num = 0;&lt;br /&gt;  static int read_num() { return num; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;the preferred C++ way to limit visibility of global objects to file scope was:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  namespace {&lt;br /&gt;&lt;br /&gt;  int num = 0;&lt;br /&gt;  int read_num() { return num; }&lt;br /&gt;&lt;br /&gt;  } // anonymous namespace&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The rationale is that you can put other symbols you wish to hide -- like class definitions -- in such a &lt;code&gt;namespace&lt;/code&gt;, but &lt;code&gt;static&lt;/code&gt; doesn't help you with those.  As the most general solution to the problem, &lt;code&gt;namespace&lt;/code&gt; wins and &lt;code&gt;static&lt;/code&gt; loses.  But I suppose that 20 years of failing to break people of the &lt;code&gt;static&lt;/code&gt; habit led to a recent change of heart.&lt;br /&gt;&lt;br /&gt;Suits me.  I had been consistently using anonymous namespaces for quite a while, both to be modern and especially since it does frequently come up that I want a type that is only used in one file.  But &lt;code&gt;static&lt;/code&gt; declarations are better for self-documenting the code, so I am happy to welcome them back.&lt;br /&gt;&lt;br /&gt;Only problem is, I need a new piece of C++ trivia to show off with.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-3019935944870201478?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=i7RsqGrBowI:SzeU_QpMsj8:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=i7RsqGrBowI:SzeU_QpMsj8:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=i7RsqGrBowI:SzeU_QpMsj8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=i7RsqGrBowI:SzeU_QpMsj8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=i7RsqGrBowI:SzeU_QpMsj8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/i7RsqGrBowI" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2011-01-26T12:19:39.885-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2011/01/c-static-no-longer-deprecated.html</feedburner:origLink></item><item><title>Emacs: Copy Environment Variable from Shell</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/cakehPqmFKU/emacs-copy-environment-variable-from.html</link><category>tips</category><category>emacs</category><category>shell</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Wed, 17 Nov 2010 08:54:00 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-6645149829144663324</guid><description>Sometimes I get annoyed when my emacs session has different environment variable settings than some shell buffer I have running in the session.  The most painful is when a Makefile depends on environment settings that I don't have in my .profile.  Command-name completion in a shell buffer can also be painful if you have changed your path.  And of course I'd like gdb to start up with the correct environment every time -- you can set the variables inside gdb, but that gets old on those days when gdb itself crashes again and again.&lt;br /&gt;
&lt;br /&gt;
I kept pasting &lt;code&gt;export FOO=bar&lt;/code&gt; into the *scratch* buffer and editing it into &lt;code&gt;(setenv "FOO" "bar")&lt;/code&gt; and eval'ing that.  After the 1000th time of doing that, I decided to automate it.  Turns out emacs already has an interactive function for copying an environment variable from the shell, but you have to type in the variable name.  I decided to write a little function to look for the last export, or the last &lt;code&gt;echo $FOO&lt;/code&gt;, and copy &lt;i&gt;that&lt;/i&gt; variable:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="font-size:75%; color:black"&gt;(defun engisneering-shell-copy-env-var ()
  (interactive)
  (let* ((expat "\\(export +\\([^=\n]+\\)=\\(.+\\)\\)")
         (echpat "\\(echo +\\$\\(.+\\)\n\\(.+\\)\\)")
         (cshpat "\\(setenv +\\([^ \n]+\\) +\\(.+\\)\\)")
         (patt (concat shell-prompt-pattern
                       "\\(" expat "\\|" echpat "\\|" cshpat "\\)")))
    (save-excursion
      (if (re-search-backward patt)
          (let* ((m (or (and (match-beginning 2) 3)
                        (and (match-beginning 5) 6) 9))
                 (var (buffer-substring (match-beginning m) (match-end m)))
                 (oldval (or (getenv var) " ")))
            (shell-copy-environment-variable var)
            (setq val (getenv var))
            (message "Old %s=%s; New %s=%s" var oldval var val))))))
&lt;/pre&gt;&lt;br /&gt;
Run this function inside your shell buffer, and it will search backwards for the last environment variable action and bring that variable setting into the emacs session.  It's also nice because it gives you a message in the minibuffer showing the change.  Add a &lt;code&gt;local-set-key&lt;/code&gt; -- I like &lt;code&gt;C-c C-v&lt;/code&gt; -- in your shell-mode-hook, and you're good to go.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-6645149829144663324?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=cakehPqmFKU:Jv8CMx0iJkA:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=cakehPqmFKU:Jv8CMx0iJkA:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=cakehPqmFKU:Jv8CMx0iJkA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=cakehPqmFKU:Jv8CMx0iJkA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=cakehPqmFKU:Jv8CMx0iJkA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/cakehPqmFKU" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2010-11-17T08:57:59.683-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2010/11/emacs-copy-environment-variable-from.html</feedburner:origLink></item><item><title>Let's Allocate Stuff!</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/oR7unbhT9PU/lets-allocate-stuff.html</link><category>c++</category><category>negative</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Wed, 22 Sep 2010 19:03:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-3124545604849968314</guid><description>Nobody's perfect, of course, but when there are &lt;i&gt;so&lt;/i&gt; many things wrong with a small piece of C++ code, it's hard to be placid.  How about:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;  std::vector&lt;std::string *&gt; v = new std::vector&lt;std::string *&gt;;
  // ...
    v-&gt;push_back(new std::string("..."));
  // ...
  std::ostream *str = get_me_a_stream(...);
  for (int i = 0; i &lt; v-&gt;size(); i++) {
    *str &lt;&lt; (*v)[i]-&gt;c_str();
  }
  delete str;
  // loop to delete v and its elements.
&lt;/pre&gt;&lt;br /&gt;
Ow, my head is spinning from all of these needless allocations.  Let's not wear out new and delete.&lt;br /&gt;
&lt;br /&gt;
Well, if you first learn C and then learn C++, your head might still be in Pointer Land.  But the unnecessary call to c_str() makes it hard for me to get any work done.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-3124545604849968314?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=oR7unbhT9PU:EgxNpAkBlf0:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=oR7unbhT9PU:EgxNpAkBlf0:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=oR7unbhT9PU:EgxNpAkBlf0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=oR7unbhT9PU:EgxNpAkBlf0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=oR7unbhT9PU:EgxNpAkBlf0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/oR7unbhT9PU" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2010-09-22T19:03:06.333-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2010/09/lets-allocate-stuff.html</feedburner:origLink></item><item><title>gcc: error: expected `)' before '&amp;' token</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/sleoJtM9z38/gcc-error-expected-before-token.html</link><category>c++</category><category>gcc</category><category>tips</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Sat, 14 Aug 2010 17:11:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-8233802266095528467</guid><description>Duplicate post here just to get two related error messages into page titles.  That's as much SEO as I know how to do.&lt;br /&gt;
&lt;br /&gt;
If you get this error from g++, and everything looks correct to you, maybe you are defining a constructor without qualifying it with the class name.  See the example on &lt;a href="http://softwareengisneering.blogspot.com/2010/08/gcc-error-expected-unqualified-id.html"&gt;this post&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-8233802266095528467?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=sleoJtM9z38:a0N88th0Fks:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=sleoJtM9z38:a0N88th0Fks:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=sleoJtM9z38:a0N88th0Fks:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=sleoJtM9z38:a0N88th0Fks:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=sleoJtM9z38:a0N88th0Fks:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/sleoJtM9z38" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2010-08-14T17:11:31.121-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2010/08/gcc-error-expected-before-token.html</feedburner:origLink></item><item><title>gcc: error: expected unqualified-id before ')' token</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/Ga7uxFiXXTw/gcc-error-expected-unqualified-id.html</link><category>c++</category><category>gcc</category><category>tips</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Sat, 14 Aug 2010 16:59:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-1268658945599984020</guid><description>I was scratching my head for a few minutes over the g++ error message in the title.  Google turned up a couple of red herrings, like &lt;a href="http://stackoverflow.com/questions/106117/gcc-expected-unqualified-id-before-token"&gt;this one&lt;/a&gt; at Stack Overflow where a clueless noob &lt;code&gt;#defined&lt;/code&gt; the name of his class.&lt;br /&gt;
&lt;br /&gt;
My mistake had been to define a constructor without putting the &lt;code&gt;Class::&lt;/code&gt; in front of it:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;
    Class() // WRONG!!!
    : Super(), _duper()
    {
    }
&lt;/pre&gt;&lt;br /&gt;
instead of&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;
    Class::Class()
    : Super(), _duper()
    {
    }
&lt;/pre&gt;&lt;br /&gt;
It wasn't as stupid as it sounds, I was cutting and pasting inlined functions into the .cpp file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-1268658945599984020?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=Ga7uxFiXXTw:C7bno7_GIoU:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=Ga7uxFiXXTw:C7bno7_GIoU:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=Ga7uxFiXXTw:C7bno7_GIoU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=Ga7uxFiXXTw:C7bno7_GIoU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=Ga7uxFiXXTw:C7bno7_GIoU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/Ga7uxFiXXTw" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2010-08-14T17:58:23.204-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2010/08/gcc-error-expected-unqualified-id.html</feedburner:origLink></item><item><title>Can't Locate Object Method via Package</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/HU0BE5ZE6xQ/cant-locate-object-method-via-package.html</link><category>tips</category><category>perl</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Wed, 14 Jul 2010 12:31:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-65937677953479212</guid><description>I recently got a confusing Perl error message for a line of code that I thought was a simple assignment to a hash member:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;Can't locate object method "patterns" via package "objdir(/[^ ]*)?" (perhaps you forgot to load "objdir(/[^ ]*)?"?) at ./filter.pl line 24.&lt;br /&gt;
&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
A Google search turned up many forum entries asking about the message, but they all had to do with open-source projects where there was indeed a package method call that had gone wrong.&lt;br /&gt;
&lt;br /&gt;
After I rubbed my eyes long enough, it was obvious what I had done:  left the '$' off the front of the hash reference.  I had typed:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;    patterns{"objdir(/[^ ]*)?"} = "dirs/objs"; # WRONG!
&lt;/pre&gt;&lt;br /&gt;
instead of:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;    $patterns{"objdir(/[^ ]*)?"} = "dirs/objs";
&lt;/pre&gt;&lt;br /&gt;
I even had &lt;code&gt;use strict; use warnings;&lt;/code&gt; on, but only got the error message.  Anyway, since Google didn't help me out, let's see if this page with the error text in the title floats to the top and helps someone else out someday.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-65937677953479212?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=HU0BE5ZE6xQ:vfFZX5IraYI:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=HU0BE5ZE6xQ:vfFZX5IraYI:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=HU0BE5ZE6xQ:vfFZX5IraYI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=HU0BE5ZE6xQ:vfFZX5IraYI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=HU0BE5ZE6xQ:vfFZX5IraYI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/HU0BE5ZE6xQ" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2010-07-14T12:31:12.820-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2010/07/cant-locate-object-method-via-package.html</feedburner:origLink></item><item><title>Blessed Mother of Commented-out Code</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/esUU8x7IcuU/blessed-mother-of-commented-out-code.html</link><category>negative</category><category>dead code</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Fri, 18 Jun 2010 14:31:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-7432322333016795444</guid><description>It's the little things in life that give pleasure, isn't it?  Like the lovely comment below, which has adorned a source file at my company for nearly sixteen (16) years now (meaning the file is at least 5 years older than the company).&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;/*****************************#if (0) //[
// Marked code has been deleted   -- XXXX (18 August, 1994)
// No need to check whether the value is X/X/X
// Only the size is to be checked which has been done
[[[ DELETED

      char  val;

      val=tolower(*((char*) var)-&gt;getValue());
      if ((val != 'X') &amp;&amp; (val != 'X') &amp;&amp; (val != 'X'))
          return 0;
]]]
   #endif //]
*************************************/
&lt;/pre&gt;&lt;br /&gt;
There are many facets to this beautiful gem.  First you'll notice that there is a nice C++-style &lt;code&gt;//&lt;/code&gt; comment -- complete with the date and the signature of Mr. XXXX -- itself commented out by a C-style &lt;code&gt;/*&lt;/code&gt; comment.  Too bad the dead code isn't commented with &lt;code&gt;//&lt;/code&gt;, so that my &lt;code&gt;grep&lt;/code&gt; for &lt;code&gt;tolower&lt;/code&gt; would have stood out as unnecessary.&lt;br /&gt;
&lt;br /&gt;
But look, really the &lt;code&gt;/*&lt;/code&gt; is there to comment out an &lt;code&gt;#if 0&lt;/code&gt;.  The guy must have wanted emacs to colorize the dead code as a comment -- I don't think emacs had font-lock back then, but there was the hilit19 package.&lt;br /&gt;
&lt;br /&gt;
Still, you can't be too careful, so let's also wrap that code up in a &lt;code&gt;[[[DELETED ... ]]]&lt;/code&gt;, in case there is some human that can't read the C comments and the if-0, but who will understand what "triple-bracket DELETED" means.&lt;br /&gt;
&lt;br /&gt;
Finally, it appears the conditional was originally written as &lt;code&gt;#if (0) [ ... ]&lt;/code&gt; -- was that ever legal C? -- but when that wouldn't compile, the brackets had to be commented out, because every character in this file is &lt;i&gt;too precious to ever delete&lt;/i&gt;.  This must be the bad code afterlife.  You can check out anytime you like, but you can never leave.&lt;br /&gt;
&lt;br /&gt;
How did all this happen?  Is it an accumulation of different commenting-out strategies that occurred over time?  Or is it just an unfortunate snapshot of one man's frenzied efforts to remove 3 lines of code without actually deleting anything?  Sadly, we can only speculate on what happened, because these lines entered our repository in exactly this condition over 10 years ago.&lt;br /&gt;
&lt;br /&gt;
I love deleting dead code, but I can't touch this one.  It's an antique.  And so ugly that it's beautiful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-7432322333016795444?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=esUU8x7IcuU:si8NAkn6v9g:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=esUU8x7IcuU:si8NAkn6v9g:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=esUU8x7IcuU:si8NAkn6v9g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=esUU8x7IcuU:si8NAkn6v9g:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=esUU8x7IcuU:si8NAkn6v9g:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/esUU8x7IcuU" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2010-06-18T14:56:22.529-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2010/06/blessed-mother-of-commented-out-code.html</feedburner:origLink></item><item><title>Csh Skips Last Line in Script</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/37U9MThGzrA/csh-skips-last-line-in-script.html</link><category>negative</category><category>csh</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Thu, 10 Jun 2010 16:55:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-6667768817381878814</guid><description>Oh, joy.&amp;nbsp; I've found another thing to &lt;a href="http://softwareengisneering.blogspot.com/2009/10/csh-dumbness.html"&gt;hate about csh&lt;/a&gt;.&amp;nbsp; If the last line of your script doesn't have a newline after it, &lt;i&gt;that line won't be executed&lt;/i&gt;.&amp;nbsp; It will be silently ignored.&amp;nbsp; That isn't very useful.&lt;br /&gt;
&lt;br /&gt;
If emacs knows you are editing a shell script, it will automatically put a newline at the end if you didn't do it yourself.&amp;nbsp; But if you have an ordinary text file that you will run with source, it better have a newline at the end.&amp;nbsp; You can get emacs to either ensure that or warn you about it by adding one of the following lines to your .emacs file:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;;; Quietly add a newline if missing.
  (setq require-final-newline t)

  ;; Ask if you want a newline at end of file.
  (setq require-final-newline 'ask)
&lt;/pre&gt;&lt;br /&gt;
Googling for this problem, I found another &lt;a href="http://www.grymoire.com/Unix/CshTop10.txt"&gt;nice csh rant&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-6667768817381878814?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=37U9MThGzrA:o7wSoSov2P0:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=37U9MThGzrA:o7wSoSov2P0:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=37U9MThGzrA:o7wSoSov2P0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=37U9MThGzrA:o7wSoSov2P0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=37U9MThGzrA:o7wSoSov2P0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/37U9MThGzrA" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2010-06-10T16:57:45.188-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2010/06/csh-skips-last-line-in-script.html</feedburner:origLink></item><item><title>Tcl Case Analysis Lunacy</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/uemm0RhWTZc/tcl-case-analysis-lunacy.html</link><category>negative</category><category>case analysis</category><category>tcl</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Wed, 28 Apr 2010 11:50:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-6560951406728726831</guid><description>This goes way back to the roots of this blog.  &lt;a href="http://softwareengisneering.blogspot.com/2008/08/tcl-is-toy-language.html"&gt;Complaining about Tcl&lt;/a&gt;, and complaining about code that breaks down into unnecessary and confusing &lt;a href="http://softwareengisneering.blogspot.com/2008/08/eschew-case-analysis.html"&gt;case analysis&lt;/a&gt; -- those topics were the first three posts here.&lt;br /&gt;
&lt;br /&gt;
Unsurprisingly, the toy language that is Tcl is serving me up some ridiculous case analysis.  It has to do with the C++-side of a Tcl integration.  When you look at the internals of the language objects created by the Tcl interpreter, some things that are conceptually the same have different internal representations.  It's bad enough that I have to succumb to case analysis to figure out what's what:  but on the other side of that wall, Tcl had to do some case analysis to put them all in different representations!  Bad, naughty Tcl.&lt;br /&gt;
&lt;br /&gt;
Here's what's bugging me.  When you look at a &lt;code&gt;Tcl_Obj&lt;/code&gt; over in the C world, it has a &lt;code&gt;typePtr&lt;/code&gt; member to distinguish different types of things:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;A simple name like &lt;code&gt;A&lt;/code&gt; has a &lt;code&gt;NULL&lt;/code&gt; typePtr.&lt;/li&gt;
&lt;li&gt;So does a list of things in braces, like &lt;code&gt;{ A B }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A name with some special characters like &lt;code&gt;A[0]&lt;/code&gt; has type "string".&lt;/li&gt;
&lt;li&gt;So does a list of things in braces which extends over a few lines, like:&lt;br /&gt;
&lt;pre&gt;{ A \
      B }
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;An explicit list like &lt;code&gt;[list A]&lt;/code&gt; has type "list".&lt;/li&gt;
&lt;li&gt;A quoted string like &lt;code&gt;"A B"&lt;/code&gt; has &lt;code&gt;NULL&lt;/code&gt;.  At least I think so.  I lost track.&lt;br /&gt;
&lt;/ul&gt;So obviously there are a bunch of &lt;code&gt;if&lt;/code&gt; statements in the back-end tangling stuff up like this.  But it's nearly impossible to untangle it on the C side.&lt;br /&gt;
&lt;br /&gt;
Stupid Tcl.  Stupid case analysis.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-6560951406728726831?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=uemm0RhWTZc:KBXMGfxb3aU:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=uemm0RhWTZc:KBXMGfxb3aU:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=uemm0RhWTZc:KBXMGfxb3aU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=uemm0RhWTZc:KBXMGfxb3aU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=uemm0RhWTZc:KBXMGfxb3aU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/uemm0RhWTZc" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2011-03-11T16:40:29.362-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2010/04/tcl-case-analysis-lunacy.html</feedburner:origLink></item><item><title>Don't Give Variables Negative Names</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/ZeSctbNun78/dont-give-variables-negative-names.html</link><category>negative</category><category>style</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Wed, 10 Mar 2010 22:23:00 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-2584012281797189358</guid><description>Sometimes programmers get caught up in the absence of something.  Don't let that leak over into the name of a variable or data member:&lt;br /&gt;
&lt;pre&gt;bool Job::acceptable(const JobCandidate &amp;applicant) const
{
  bool noFelonyConvictions = findFelonyConvictions(applicant);
  return noFelonyConvictions &amp;&amp; qualified(applicant);
}
&lt;/pre&gt;The &lt;code&gt;noFelonyConvictions&lt;/code&gt; variable documents the code in a readable way, but it gets silly if the code ever changes so that you have to initialize it, or if someone ever wants to know if there &lt;i&gt;are&lt;/i&gt; felony convictions.  Things become less readable:&lt;br /&gt;
&lt;pre&gt;  bool noFelonyConvictions = true;
  if (applicant.findRecords(FELONY)) {
    noFelonyConvictions = false;
  }
  return applicant.qualified(!noFelonyConvictions);
&lt;/pre&gt;It all makes more sense if you name the variable &lt;code&gt;felonyConvictions&lt;/code&gt;, which initializes naturally enough to false, can be set to true if one is found, and can be negated to show absence.  Also, if you later become interested in the number of convictions, there will be fewer code changes if the variable changes from a &lt;code&gt;bool&lt;/code&gt; to an &lt;code&gt;int&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
Whenever you notice yourself putting a "no" into a variable name, get rid of it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-2584012281797189358?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=ZeSctbNun78:Ygu6aq2eECY:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=ZeSctbNun78:Ygu6aq2eECY:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=ZeSctbNun78:Ygu6aq2eECY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=ZeSctbNun78:Ygu6aq2eECY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=ZeSctbNun78:Ygu6aq2eECY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/ZeSctbNun78" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2010-03-10T22:27:02.868-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2010/03/dont-give-variables-negative-names.html</feedburner:origLink></item><item><title>How to Undeclare a bash Function</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/8S4CGggDinw/how-to-undeclare-bash-function.html</link><category>bash</category><category>tips</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Thu, 04 Feb 2010 17:47:00 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-3165032496881257158</guid><description>It took me a few minutes to figure this out, so I thought I might as well pass it along.&lt;br /&gt;
&lt;br /&gt;
If you've declared a bash function, and then decided you don't really want it, either because you went ahead and implemented it as a script somewhere, or you gave it a bad name or something, you undeclare it like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;  $ unset -f myfunc
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-3165032496881257158?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=8S4CGggDinw:sD-8W6x9TpA:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=8S4CGggDinw:sD-8W6x9TpA:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=8S4CGggDinw:sD-8W6x9TpA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=8S4CGggDinw:sD-8W6x9TpA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=8S4CGggDinw:sD-8W6x9TpA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/8S4CGggDinw" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2010-02-04T17:47:56.903-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2010/02/how-to-undeclare-bash-function.html</feedburner:origLink></item><item><title>Nice Code Structure</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/6KwmN3J4RuE/nice-code-structure.html</link><category>c++</category><category>negative</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Mon, 01 Feb 2010 16:29:00 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-2527614379265305248</guid><description>Here's a brilliant one I just ran across at work (variables changed to protect the... to protect someone):&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;  for (i = 0; i &lt; lim; i++) {
    if (someCondition(n[i])) {
      warn("you can't do that");
      continue;
    }
    switch (n[i].type()) {
      default:
        nn = 0;
        warn("we're ignoring this");
        break;
    }
    orig-&gt;doSomethingWith(nn);
    delete nn;
  }
&lt;/pre&gt;&lt;br /&gt;
How do you like that &lt;code&gt;switch&lt;/code&gt; with only a &lt;code&gt;default&lt;/code&gt; branch?  Pretty cool, huh?  Almost is nice is the &lt;code&gt;delete&lt;/code&gt; that only ever sees a &lt;code&gt;NULL&lt;/code&gt;.  Then when I realized &lt;code&gt;doSomethingWith()&lt;/code&gt; is a no-op if it gets a &lt;code&gt;NULL&lt;/code&gt;, I felt even luckier.&lt;br /&gt;
&lt;br /&gt;
Look, if you're making such a big change to some code that you take out &lt;i&gt;all&lt;/i&gt; the branches of a &lt;code&gt;switch&lt;/code&gt;, isn't it worth a couple minutes to clean this up and show what is really happening?  After all, the code really does this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;  for (i = 0; i &lt; lim; i++) {
    if (someCondition(n[i])) {
      warn("you can't do that");
    }
    else {
      warn("we're ignoring this");
    }
  }
&lt;/pre&gt;

It probably makes sense to only give the second warning, since who cares if you can't do it, when really it would only be ignored anyway.  And at that point you might wonder why you need to give the same warning &lt;code&gt;lim&lt;/code&gt; times.&lt;br /&gt;
&lt;br /&gt;
Ugly code kills.  Kill ugly code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-2527614379265305248?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=6KwmN3J4RuE:yeJb6dmxou8:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=6KwmN3J4RuE:yeJb6dmxou8:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=6KwmN3J4RuE:yeJb6dmxou8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=6KwmN3J4RuE:yeJb6dmxou8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=6KwmN3J4RuE:yeJb6dmxou8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/6KwmN3J4RuE" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2010-02-01T16:29:22.629-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2010/02/nice-code-structure.html</feedburner:origLink></item><item><title>Emacs vs. Nicer dirs</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/kAgHaeZ_P8U/emacs-vs-nicer-dirs.html</link><category>tips</category><category>emacs</category><category>shell</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Fri, 11 Dec 2009 09:43:00 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-1799461363142636897</guid><description>In the last post I described a &lt;a href="http://softwareengisneering.blogspot.com/2009/11/nicer-pushd-popd-and-dirs.html"&gt;nicer version&lt;/a&gt; of the shell &lt;code&gt;dirs&lt;/code&gt; command that labels each directory with its position, so that you can &lt;code&gt;pushd&lt;/code&gt; directly to the one you want.&lt;br /&gt;&lt;br /&gt;One problem with it is that emacs shell-mode generally uses &lt;code&gt;dirs&lt;/code&gt; to track which directory you're in.  And you do want it to track directories for you.  Our nicer version of &lt;code&gt;dirs&lt;/code&gt; produces output that isn't readable to emacs.&lt;br /&gt;&lt;br /&gt;Of course the natural solution is:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (setq shell-dirstack-query "command dirs")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;to pick up the shell's builtin &lt;code&gt;dirs&lt;/code&gt;.  Sadly, you can't just throw that line into your .emacs file, because shell-mode sets &lt;code&gt;shell-dirstack-query&lt;/code&gt; every time you start a new shell.  It sets it &lt;span style="font-style: italic;"&gt;unconditionally and globally&lt;/span&gt;, which is a ridiculous design flaw, but that's how it goes.  There is no hook that runs after it sets the value, either.&lt;br /&gt;&lt;br /&gt;So you're stuck with needing a workaround:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Name your command something other than &lt;code&gt;dirs&lt;/code&gt; .&lt;/li&gt;&lt;li&gt;Use a flag on your new &lt;code&gt;dirs&lt;/code&gt; to get the nicer behavior.&lt;/li&gt;&lt;li&gt;Write your own emacs function to start a shell:&lt;/li&gt;&lt;/ol&gt;&lt;pre&gt;&lt;br /&gt;  (defun engisneering-shell ()&lt;br /&gt;    (interactive)&lt;br /&gt;    (shell)&lt;br /&gt;    (setq shell-dirstack-query "command dirs"))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-1799461363142636897?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=kAgHaeZ_P8U:u9SgFdquT2w:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=kAgHaeZ_P8U:u9SgFdquT2w:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=kAgHaeZ_P8U:u9SgFdquT2w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=kAgHaeZ_P8U:u9SgFdquT2w:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=kAgHaeZ_P8U:u9SgFdquT2w:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/kAgHaeZ_P8U" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2009-12-11T09:54:48.490-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2009/12/emacs-vs-nicer-dirs.html</feedburner:origLink></item><item><title>Nicer pushd, popd, and dirs</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/99Dqn5KJz4w/nicer-pushd-popd-and-dirs.html</link><category>bash</category><category>tips</category><category>shell</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Tue, 17 Nov 2009 16:38:00 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-6847961066189305331</guid><description>Writing up the safer, friendlier &lt;a href="http://softwareengisneering.blogspot.com/2009/10/bash-vs-which.html"&gt;bash &lt;code&gt;which&lt;/code&gt;&lt;/a&gt; command reminded me of another wrapper function that's handy to have.  If you use &lt;code&gt;pushd/popd&lt;/code&gt; to keep a stack of directories in your shell window, sometimes you want to switch to a directory far down the stack.  If you want to switch to the third directory down, you do &lt;code&gt;pushd +3&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;The problem is, you have to count along the list of directories, since &lt;code&gt;dirs, pushd,&lt;/code&gt; and &lt;code&gt;popd&lt;/code&gt; all just spit out a one-line list of the stack, like this:&lt;pre&gt;&lt;br /&gt;  $ dirs&lt;br /&gt;  /usr/local/share ~ ~/work ~/tmp&lt;br /&gt;&lt;/pre&gt;Not an impossible task, but it can get annoying if you have some long paths in there, especially once your stack gets past two or three deep.  Why not have &lt;code&gt;dirs&lt;/code&gt; print one directory per line, and label them with their depths?  To do so, add this function to your &lt;code&gt;.bashrc&lt;/code&gt; file:&lt;pre&gt;&lt;br /&gt;  function dirs {&lt;br /&gt;      ds=(`command dirs`)&lt;br /&gt;      i=0&lt;br /&gt;      while [ "${ds[$i]}" != "" ]; do&lt;br /&gt;          echo $i: ${ds[$i]};&lt;br /&gt;          i=$((i+1));&lt;br /&gt;      done&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;Now you get more readable output:&lt;pre&gt;&lt;br /&gt;  $ dirs&lt;br /&gt;  0: /usr/local/share&lt;br /&gt;  1: ~&lt;br /&gt;  2: ~/work&lt;br /&gt;  3: ~/tmp&lt;br /&gt;&lt;/pre&gt;If you want to remove &lt;code&gt;~/work&lt;/code&gt; from the stack, just do &lt;code&gt;popd +2&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Since &lt;code&gt;pushd&lt;/code&gt; and &lt;code&gt;popd&lt;/code&gt; also print the directory stack, let's add the same style of output to them:&lt;pre&gt;&lt;br /&gt;  function pushd {&lt;br /&gt;      if command pushd $@ &gt; /dev/null; then&lt;br /&gt;          dirs&lt;br /&gt;      fi&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  function popd {&lt;br /&gt;      if command popd $@ &gt; /dev/null; then&lt;br /&gt;          dirs&lt;br /&gt;      fi&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;One final note.  In case some wacky systemwide file has aliased these commands to something else, add the following unaliasing code to the top of your .bashrc:&lt;pre&gt;&lt;br /&gt;  for func in dirs pushd popd; do&lt;br /&gt;      if alias $func &gt; /dev/null 2&gt;&amp;1 ; then unalias $func; fi&lt;br /&gt;  done&lt;br /&gt;&lt;/pre&gt;Otherwise, your functions will be hidden (aliases take precedence).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;PS: emacs shell-mode has a conflict with this dirs:&lt;/span&gt; here's how to &lt;a href="http://softwareengisneering.blogspot.com/2009/12/emacs-vs-nicer-dirs.html"&gt;fix it&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-6847961066189305331?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=99Dqn5KJz4w:qM1Lw-YESX4:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=99Dqn5KJz4w:qM1Lw-YESX4:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=99Dqn5KJz4w:qM1Lw-YESX4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=99Dqn5KJz4w:qM1Lw-YESX4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=99Dqn5KJz4w:qM1Lw-YESX4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/99Dqn5KJz4w" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2009-12-11T09:57:32.255-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2009/11/nicer-pushd-popd-and-dirs.html</feedburner:origLink></item><item><title>Keep from Killing Emacs Shell Buffers</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/1hGgS_oYJmM/keep-from-killing-emacs-shell-buffers.html</link><category>tips</category><category>emacs</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Mon, 02 Nov 2009 10:05:00 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-7758925682850841169</guid><description>If you're someone who lives in emacs like I do, then you probably rely on shell buffers (&lt;code&gt;M-x shell&lt;/code&gt;) to interact with the operating system.  That way you can search through output and edit history commands in a natural way that a mere terminal doesn't allow.&lt;br /&gt;&lt;br /&gt;But occasionally I've been left kicking the wall after accidentally killing a shell buffer that had lots of work in it that I still needed.  It really hurts when you accidentally kill a buffer where you're waiting for a long-running process to finish.  To prevent industrial accidents like that, add a guard to &lt;code&gt;kill-buffer-hook&lt;/code&gt; in your .emacs file:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  (add-hook 'kill-buffer-hook&lt;br /&gt;    '(lambda()&lt;br /&gt;       (and&lt;br /&gt;         (string= "Shell" mode-name)&lt;br /&gt;         (or&lt;br /&gt;           (yes-or-no-p&lt;br /&gt;             (format "Kill buffer `%s'? " (buffer-name)))&lt;br /&gt;           (error "Aborted")))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you really &lt;i&gt;do&lt;/i&gt; want to kill the shell buffer, type "yes", and you're done.  But it will save you some grief if you just hit &lt;code&gt;C-x k&lt;/code&gt; in the wrong buffer.&lt;br /&gt;&lt;br /&gt;What's more common for me is that my eyes are on a file that I want to refresh or replace with &lt;code&gt;C-x C-v (find-alternate-file)&lt;/code&gt;, but the cursor is in a shell buffer.  In that case, emacs will indeed load the alternate file, and you'll be asked "Kill buffer ` **lose**'?"  Say no, then you'll have &lt;code&gt;C-x b&lt;/code&gt; to " **lose**" (note the leading space), and rename the shell buffer to "*shell*" or whatever you had previously named it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-7758925682850841169?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=1hGgS_oYJmM:4QYqalinMEA:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=1hGgS_oYJmM:4QYqalinMEA:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=1hGgS_oYJmM:4QYqalinMEA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=1hGgS_oYJmM:4QYqalinMEA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=1hGgS_oYJmM:4QYqalinMEA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/1hGgS_oYJmM" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2009-11-02T11:07:14.375-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2009/11/keep-from-killing-emacs-shell-buffers.html</feedburner:origLink></item><item><title>Bash vs. Which</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/SAm8gX3n_Ds/bash-vs-which.html</link><category>bash</category><category>tips</category><category>shell</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Mon, 26 Oct 2009 13:03:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-5099015712087970393</guid><description>The Unix &lt;code&gt;which&lt;/code&gt; command is useful for searching your &lt;code&gt;$PATH&lt;/code&gt; to find which version of an executable is going to run.  But did you know that it doesn't always tell you the truth?  For instance, it doesn't tell you when the command you're asking about is hidden by a shell builtin (or function, keyword, or alias):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  $ which echo&lt;br /&gt;  /usr/bin/echo&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;which&lt;/code&gt; found /usr/bin/echo on your path, but &lt;code&gt;echo&lt;/code&gt; is a shell builtin (at least in bash), so that's what will get run, not the one on the path.  The GNU man page for &lt;code&gt;which&lt;/code&gt; presents workarounds that will pick up functions and aliases, but shell builtins still slip through the cracks.  The situation is even weirder on Solaris, where &lt;code&gt;which&lt;/code&gt; is a &lt;b&gt;csh&lt;/b&gt; shell-script, that sources your &lt;code&gt;.cshrc&lt;/code&gt; file as part of its operation -- very strange if your shell is bash.&lt;br /&gt;&lt;br /&gt;Clearly, &lt;code&gt;which&lt;/code&gt; is not to be trusted.  The easiest workaround, if you use bash, is the &lt;code&gt;type&lt;/code&gt; builtin:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  $ type -a echo&lt;br /&gt;  echo is a shell builtin&lt;br /&gt;  echo is /bin/echo&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A slightly nicer workaround is to make a &lt;code&gt;bash&lt;/code&gt; function for &lt;code&gt;which&lt;/code&gt;, that uses &lt;code&gt;type&lt;/code&gt; to do the right thing.  I also like &lt;code&gt;which&lt;/code&gt; to do an &lt;code&gt;ls -l&lt;/code&gt; where applicable.  Here's what I have in my .bashrc:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  if alias which &gt; /dev/null 2&gt;&amp;1; then unalias which; fi&lt;br /&gt;&lt;br /&gt;  function which {&lt;br /&gt;      hash -r&lt;br /&gt;      t=`type -t $@`&lt;br /&gt;&lt;br /&gt;      if [ -z "${t%%file*}" ]; then&lt;br /&gt;          for p in `type -p $@`; do&lt;br /&gt;              ls -l ${p};&lt;br /&gt;          done&lt;br /&gt;      else&lt;br /&gt;          type $@;&lt;br /&gt;      fi&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now &lt;code&gt;which&lt;/code&gt; gives you much more information:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  $ which -a wish&lt;br /&gt;  lrwxrwxrwx  1 root  root  13 Dec 23 2008 /usr/local/bin/wish -&gt; /usr/bin/wish*&lt;br /&gt;  lrwxrwxrwx  1 root  root   7 Jan  8 2007 /usr/bin/wish -&gt; wish8.3*&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The unalias protects you in case some systemwide .bashrc or .profile aliases which in some way (unlikely, but good hygiene anyway).  The call to &lt;code&gt;hash&lt;/code&gt; clears the hashed function list, so that any changes to your PATH are reflected.  The reason for the &lt;code&gt;if&lt;/code&gt; statement in the function, is that we certainly want to report builtins, functions, etc., but if there are none, we can use &lt;code&gt;type -p&lt;/code&gt; to make it easier to pass the filenames to &lt;code&gt;ls -l&lt;/code&gt;.  If there are builtins or such, we just punt and give the unaltered &lt;code&gt;type&lt;/code&gt; output.&lt;br /&gt;&lt;br /&gt;You can pass &lt;code&gt;-a&lt;/code&gt; to this &lt;code&gt;which&lt;/code&gt; if you want to see all the matches for the command, in order of precedence.&lt;br /&gt;&lt;br /&gt;Note that this has to be a function, not a script, because running the script will source your .bashrc, which might change the PATH (all PATH changes should be in .profile, but sometimes people do it in .bashrc).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-5099015712087970393?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=SAm8gX3n_Ds:Mk528DnzbEo:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=SAm8gX3n_Ds:Mk528DnzbEo:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=SAm8gX3n_Ds:Mk528DnzbEo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=SAm8gX3n_Ds:Mk528DnzbEo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=SAm8gX3n_Ds:Mk528DnzbEo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/SAm8gX3n_Ds" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2009-11-17T16:26:00.409-08:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2009/10/bash-vs-which.html</feedburner:origLink></item><item><title>Csh Stupidity</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/hPFRBL46pyk/csh-dumbness.html</link><category>negative</category><category>csh</category><category>shell</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Fri, 02 Oct 2009 16:54:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-8489798223027707983</guid><description>One of the great things about the Linux era, is that bash seems to be taking over as the preferred shell to use, instead of csh/tcsh.  The projects at my current job began during the SunOS era, so when I started there a couple years ago I went with the flow and let the sysadmin set up my default as tcsh just like everyone else there uses.  When I was getting started, no one had a reasonable .profile or .bashrc I could use, so I went with tcsh so I could use the tribal .cshrc.&lt;br /&gt;
&lt;br /&gt;
In terminals, the first command I run is "bash"; most of my work is in an emacs shell window, so my .emacs says &lt;code&gt;(setq shell-file-name "/bin/bash")&lt;/code&gt; -- actually there's an (if) in there to choose cygwin's bash if I happen to be on Windows.  I do a lot of shell programming at the command line, and I simply can't live with csh-style programming.&lt;br /&gt;
&lt;br /&gt;
A few days ago I was working on my .cshrc file, and I noticed how dim-witted csh's if-else handling is.  The classic anti-csh diatribe is &lt;a href="http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/"&gt;Csh Programming Considered Harmful&lt;/a&gt;, which is an entertaining read, but there's some insanity that isn't even covered in that worthy rant.  Let me start by presenting a correct csh script:&lt;br /&gt;
&lt;pre&gt;setenv FOO hello
if ($FOO == hello) then
echo hi
else if ($FOO == goodbye) then
echo see ya
endif
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Source that script, and the output is:&lt;br /&gt;
&lt;pre&gt;hi
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Various typos can have effects on this script that range from annoying to silent but deadly.  Here's an annoying one:  put the second &lt;code&gt;if&lt;/code&gt; on a different line from the &lt;code&gt;else&lt;/code&gt;.  The output is:&lt;br /&gt;
&lt;pre&gt;hi
else: endif not found.
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Well, at least you got an error message telling you something is up, although requiring two keywords to be on the same line is a level of stupidity worthy of Tcl.  What if you do the opposite, and have too many &lt;code&gt;endifs&lt;/code&gt;?  Well, the output is just "hi", with no error message.  I suppose that doesn't bite too much, until later when you nest another &lt;code&gt;if&lt;/code&gt; into the script, and it suddenly gets closed by one of your stealth extra &lt;code&gt;endifs&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
But here's a bad one.  Take the original script.  Add an &lt;code&gt;else&lt;/code&gt; at the beginning, and an &lt;code&gt;endif&lt;/code&gt; at the end.  Seems like an &lt;code&gt;else&lt;/code&gt; without an accompanying &lt;code&gt;if&lt;/code&gt; should get a syntax error, but it doesn't.  The extra &lt;code&gt;endif&lt;/code&gt; -- which might have been there because we always had an extra one, but never got an error about it -- closes the weird &lt;code&gt;else&lt;/code&gt;.  And guess what?  The script runs with no errors, and &lt;i&gt;no output&lt;/i&gt;.  The &lt;code&gt;else&lt;/code&gt; is kind of a "if not true".  How can this be a good thing?&lt;br /&gt;
&lt;br /&gt;
I did these experiments with &lt;code&gt;csh&lt;/code&gt; and &lt;code&gt;tcsh&lt;/code&gt; on RedHat.  Avoid &lt;code&gt;csh&lt;/code&gt;.  Long live &lt;code&gt;bash&lt;/code&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-8489798223027707983?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=hPFRBL46pyk:2Gj71jaPV5k:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=hPFRBL46pyk:2Gj71jaPV5k:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=hPFRBL46pyk:2Gj71jaPV5k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=hPFRBL46pyk:2Gj71jaPV5k:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=hPFRBL46pyk:2Gj71jaPV5k:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/hPFRBL46pyk" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2010-06-10T16:56:13.793-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2009/10/csh-dumbness.html</feedburner:origLink></item><item><title>Makedepend: Error: Failed to Read ...</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/xXo7kSAsAfU/makedepend-error-failed-to-read.html</link><category>negative</category><category>make</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Mon, 21 Sep 2009 16:56:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-7844140646535883871</guid><description>I &lt;a href="http://softwareengisneering.blogspot.com/2008/12/stupid-stupid-makedepend.html"&gt;complained&lt;/a&gt; a few months ago about &lt;code&gt;makedepend&lt;/code&gt; not picking up dependencies, and gave a recipe for avoiding makedepend.&lt;br /&gt;&lt;br /&gt;I'm stuck with it for a project, and a couple of times I've gotten a makedepend failure, with only this useless warning:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;makedepend: error:  failed to read [some directory name]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The problem ended up being an &lt;code&gt;#include&lt;/code&gt; somewhere, where the opening double-quote (&lt;code&gt;"&lt;/code&gt;) was missing.  One time I accidentally had a single-quote at the beginning, closed with a double-quote; the other time a co-worker left off the opening quote, but did have the closing quote.&lt;br /&gt;&lt;br /&gt;No help from makedepend on &lt;i&gt;which&lt;/i&gt; file has the faulty include: it just gives up on the whole directory.  Thanks, makedepend.  Notice that if you leave off both quotes, or have both as single-quotes, makedepend is kind enough to give you a meaningful message.  Or, if you open with a double-quote, and forget the closing quote, it exits without an error!  Though I'm not sure if it gets the dependencies right in that case.&lt;br /&gt;&lt;br /&gt;Do yourself a favor, use gcc's &lt;a href="http://softwareengisneering.blogspot.com/2008/12/stupid-stupid-makedepend.html"&gt;dependency-generating scheme&lt;/a&gt;, and never use makedepend again.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-7844140646535883871?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=xXo7kSAsAfU:O089-ouZCIQ:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=xXo7kSAsAfU:O089-ouZCIQ:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=xXo7kSAsAfU:O089-ouZCIQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=xXo7kSAsAfU:O089-ouZCIQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=xXo7kSAsAfU:O089-ouZCIQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/xXo7kSAsAfU" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2009-09-21T17:31:37.752-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2009/09/makedepend-error-failed-to-read.html</feedburner:origLink></item><item><title>Perl Cwd Performance</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/Xgi866y3x28/perl-cwd-performance.html</link><category>positive</category><category>perl</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Wed, 15 Jul 2009 10:20:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-7458043529430776018</guid><description>The &lt;a href="http://www.amazon.com/Programming-Perl-3rd-Larry-Wall/dp/0596000278?&amp;camp=212361&amp;linkCode=wey&amp;tag=itspuni-20&amp;creative=380733"&gt;Camel book&lt;/a&gt; says -- in the Efficiency section of Chapter 24 -- to use the &lt;code&gt;Cwd&lt;/code&gt; module instead of calling &lt;code&gt;pwd&lt;/code&gt; repeatedly.&lt;br /&gt;&lt;br /&gt;Boy, it's not kidding.  I wrote a test script that does almost nothing but change directories and print the current directory, repeating that about 7500 times.  Using &lt;code&gt;`pwd`&lt;/code&gt; to get the directory took an average wall-clock time of 11.7 seconds.  If instead you import &lt;code&gt;Cwd&lt;/code&gt;'s version of &lt;code&gt;chdir()&lt;/code&gt;, the script can use &lt;code&gt;$ENV{PWD}&lt;/code&gt;, which took an average wall-clock time of 0.3 seconds.&lt;br /&gt;&lt;br /&gt;Oddly, using &lt;code&gt;Cwd::cwd()&lt;/code&gt; took an average of 15.4 seconds.  This wasn't a very scientific test, but those numbers bore up under repeated tries (doing several runs in a row, throwing out the time for the first run).  I used wall-clock time, because the sys/user time reported by Unix &lt;code&gt;time&lt;/code&gt; was quite a bit lower, even though it was an unloaded system.  Maybe because the directories were NFS mounts.&lt;br /&gt;&lt;br /&gt;So here's a good strategy for using &lt;code&gt;Cwd&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  use Cwd qw(chdir);&lt;br /&gt;  sub cwd {&lt;br /&gt;    return $ENV{PWD};&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note: the &lt;code&gt;Cwd&lt;/code&gt; documentation points out that &lt;code&gt;$ENV{PWD}&lt;/code&gt; is only kept up to date if every module used in the script uses &lt;code&gt;Cwd::chdir&lt;/code&gt; to change directories.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-7458043529430776018?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=Xgi866y3x28:byDVfymR0Mw:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=Xgi866y3x28:byDVfymR0Mw:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=Xgi866y3x28:byDVfymR0Mw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=Xgi866y3x28:byDVfymR0Mw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=Xgi866y3x28:byDVfymR0Mw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/Xgi866y3x28" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2009-07-15T10:49:06.742-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2009/07/perl-cwd-performance.html</feedburner:origLink></item><item><title>gcc Warning Options</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/yirI5A27tHA/gcc-warning-options.html</link><category>c++</category><category>gcc</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Mon, 06 Jul 2009 17:49:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-205752762524778210</guid><description>A few years ago I was in a job interview, and the development manager was gloating because he had squashed all compiler warnings in the code, and then added the gcc &lt;code&gt;-Werror&lt;/code&gt; switch to the build, so that warnings now caused the build to fail.  At the time, I thought "That's annoying overkill".  My feeling was that compiler warnings didn't live very long -- after someone saw one a few times, they would fix it.&lt;br /&gt;&lt;br /&gt;But I've changed my mind.  Where I work, the team had even been doing without &lt;code&gt;-Wall&lt;/code&gt; for many years.  They &lt;i&gt;had&lt;/i&gt; been using &lt;code&gt;-pedantic&lt;/code&gt;.  In other words, the warnings were all noise, and no signal, since the pedantic warnings don't tell you about potential bugs in your code, just about adherence to language standards.  Moreover, they were completely happy to ignore all compiler warnings -- even those for things so dangerous that gcc warns about them without any warning switches, like 64-bit size issues.  I now understand why someone would insist on &lt;code&gt;-Werror&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Really, the best set of warnings for g++ is &lt;code&gt;-Wall -Wextra -Werror&lt;/code&gt;.  [If you have an older gcc, like the 3.2.3 that's stock on RedHat 3, use &lt;code&gt;-W&lt;/code&gt; instead of &lt;code&gt;-Wextra&lt;/code&gt;.]  When we switched these on recently, there were &lt;i&gt;thousands&lt;/i&gt; of unique warnings.  Many of them were harmless in the end of the day, but there were dozens that indicated serious code bugs and/or crashes waiting to happen.&lt;br /&gt;&lt;br /&gt;Of course, you can disable some of the &lt;code&gt;-Wextra&lt;/code&gt; warnings.  On our RedHat 3 build, we find it convenient to add these disabling flags:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;-Wno-parentheses&lt;/code&gt;: too picky&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;-Wno-unused-parameter&lt;/code&gt;: provoked by &amp;lt;fstream&amp;gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;-Wno-deprecated&lt;/code&gt;: provoked by &amp;lt;strstream&amp;gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In the best possible world, we would use &amp;lt;sstream&amp;gt; and wouldn't need &lt;code&gt;-Wno-deprecated&lt;/code&gt;.  But that's a battle for another day.  For today, I'm just very happy that we have real warnings turned on, and that they get attention due to &lt;code&gt;-Werror&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-205752762524778210?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=yirI5A27tHA:3fIjyr_7J2Y:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=yirI5A27tHA:3fIjyr_7J2Y:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=yirI5A27tHA:3fIjyr_7J2Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=yirI5A27tHA:3fIjyr_7J2Y:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=yirI5A27tHA:3fIjyr_7J2Y:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/yirI5A27tHA" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2009-07-06T18:57:45.641-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2009/07/gcc-warning-options.html</feedburner:origLink></item><item><title>Emacs Registers</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/RYis5PFY94c/emacs-registers.html</link><category>emacs</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Mon, 18 May 2009 23:22:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-1768242652835207047</guid><description>A few weeks ago when I was &lt;a href="http://softwareengisneering.blogspot.com/2009/02/getting-back-to-where-you-were-in-emacs.html"&gt;talking&lt;/a&gt; about tricks to get back to your editing location in emacs, I neglected to mention the jump-to-register command, by default bound to &lt;code&gt;C-x r j&lt;/code&gt;.  Actually, the first step is to save a location to a register: &lt;code&gt;C-x r SPC&lt;/code&gt; (point-to-register).  You'll be prompted to enter a character to refer to the location.&lt;br /&gt;&lt;br /&gt;The nice thing is, when you jump-to-register, you don't have to be in the same buffer or file as the saved location.  So you can mark places that are interesting, go explore some other stuff, and then immediately leap back to the buffer and line that you need.&lt;br /&gt;&lt;br /&gt;Do you use emacs registers much?  There are a few things you can do with them, the most common being point-to-register/jump-to-register and copy-to-register/insert-register.  Whereas the kill-ring is like a text clipboard vector, copy-to- and insert-register are like a clipboard associative array.&lt;br /&gt;&lt;br /&gt;I find it useful to keep register identifiers (the single character that names a register) partitioned into namespaces:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;punctuation marks: &lt;/span&gt;canned useful strings defined with set-register that my .emacs loads at startup&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;numbers:&lt;/span&gt; locations for jump-to-register&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;letters&lt;span style="font-weight: bold;"&gt;: &lt;/span&gt;&lt;/span&gt;temporary copy-to-register strings for ad hoc cut/paste operations&lt;/li&gt;&lt;/ul&gt;It was only a few weeks ago that I realized that control-keystrokes or meta-keystrokes can be register names.  It probably makes more sense to let the letter namespace represent canned strings along with punctuation marks, and use control characters for the quotidian things that letters represent for me right now.  I might gradually shift to that way of doing business.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-1768242652835207047?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=RYis5PFY94c:OhtoNGBbGNc:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=RYis5PFY94c:OhtoNGBbGNc:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=RYis5PFY94c:OhtoNGBbGNc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=RYis5PFY94c:OhtoNGBbGNc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=RYis5PFY94c:OhtoNGBbGNc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/RYis5PFY94c" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2009-05-18T23:44:01.699-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2009/05/emacs-registers.html</feedburner:origLink></item><item><title>Handy C++ Visitor Macros</title><link>http://feedproxy.google.com/~r/SoftwareEngisneering/~3/qbASeUK4w30/handy-c-visitor-macros.html</link><category>c++</category><category>visitor</category><author>noreply@blogger.com (Bill Night)</author><pubDate>Sun, 03 May 2009 21:30:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-837664636726682837.post-6145534857666444118</guid><description>This is the fifth post on the subject of the Visitor design pattern.  First I tried to explain the &lt;a href="http://softwareengisneering.blogspot.com/2009/03/c-visitor-pattern-motivation.html"&gt;motivation&lt;/a&gt; for Visitor, then presented the &lt;a href="http://softwareengisneering.blogspot.com/2009/03/c-visitors-basic-implementation.html"&gt;textbook implementation&lt;/a&gt;, what I consider to be some &lt;a href="http://softwareengisneering.blogspot.com/2009/04/easier-to-use-c-visitors.html"&gt;improvements&lt;/a&gt; on that implementation, and finally &lt;a href="http://softwareengisneering.blogspot.com/2009/05/default-visitor-idiom.html"&gt;an example&lt;/a&gt; of the power of the Default Visitor variant of the design pattern.  In this post, I want to show some preprocessor macros that make Visitor even handier.  Brace yourself, this is going to be a long post.  There's a lot to discuss.&lt;br /&gt;&lt;br /&gt;The C preprocessor is a dangerous weapon when used indiscriminately.  In the case of our C++ Visitors, however, some preprocessor magic will provide us with the following benefits:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Compiler errors (not warnings) when a concrete Visitor class has not been defined correctly.&lt;/li&gt;&lt;li&gt;Automatic generation of tedious parts of the Default Visitor implementation.&lt;/li&gt;&lt;li&gt;Linker errors when Visitors which &lt;span style="font-style: italic;"&gt;must not&lt;/span&gt; implement Default Visitor are not updated to visit a newly-added class.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;We need to add the Statement hierarchy described in the last post to the Visitor class we declared earlier.  Instead of hand-coding everything, we are going to write a header file that uses some preprocessor macros to describe the hierarchy of visited classes.  If we also add a header file containing &lt;code&gt;#include&lt;/code&gt; directives for each concrete visited class, then we won't have to edit Visitor.hpp or Visitor.cpp when we add classes to the hierarchy in the future.  Nifty!&lt;br /&gt;&lt;br /&gt;Let's call the first header file &lt;code&gt;VisitorSpecs.hpp&lt;/code&gt;.  It looks like this:&lt;pre&gt;&lt;br /&gt;// NOTE: No include guard for this header!&lt;br /&gt;&lt;br /&gt;#ifndef VISITED_ABSTRACT_CLASS&lt;br /&gt;#define VISITED_ABSTRACT_CLASS(cls,parent)&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;#ifndef VISITED_ROOT_CLASS&lt;br /&gt;#define VISITED_ROOT_CLASS(cls) \&lt;br /&gt;  VISITED_ABSTRACT_CLASS(cls,0)&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;VISITED_ROOT_CLASS(Expression)&lt;br /&gt;VISITED_CLASS(Variable, Expression)&lt;br /&gt;VISITED_CLASS(Number, Expression)&lt;br /&gt;VISITED_CLASS(Operation, Expression)&lt;br /&gt;&lt;br /&gt;VISITED_ROOT_CLASS(Statement)&lt;br /&gt;VISITED_CLASS(Assignment, Statement)&lt;br /&gt;VISITED_ABSTRACT_CLASS(MultiStatement, Statement)&lt;br /&gt;VISITED_CLASS(Block, MultiStatement)&lt;br /&gt;VISITED_CLASS(IfElse, MultiStatement)&lt;br /&gt;&lt;br /&gt;#undef VISITED_ROOT_CLASS&lt;br /&gt;#undef VISITED_ABSTRACT_CLASS&lt;br /&gt;#undef VISITED_CLASS&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Hang on a second... This defines a couple of macros as no-ops, and leaves another macro undefined.  What gives?  The answer is that Visitor.hpp defines the macros one way before including VisitorSpecs.hpp, and Visitor.cpp defines the macros another way, and &lt;i&gt;also includes VisitorSpecs.hpp&lt;/i&gt;.  That's why the header must not have an include guard:  it will get included into Visitor.cpp multiple times.  You may even find other consumers for VisitorSpecs.hpp, as you'll see a little later.&lt;br /&gt;&lt;br /&gt;The macros are going to end up a little bit complicated, to provide some of the wonderful compiler fail-safes I've been hyping.  But to make things clear, let's present the basic implementation first.  Visitor.hpp has to include VisitorSpecs.hpp two separate times.  First to declare the class names:&lt;pre&gt;&lt;br /&gt;#define VISITED_CLASS(cls,parent) class cls;&lt;br /&gt;#define VISITED_ABSTRACT_CLASS(cls, parent) \&lt;br /&gt;  VISITED_CLASS(cls,parent)&lt;br /&gt;#include "VisitorSpecs.hpp"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then to declare the member functions, Visitor.hpp defines the macros as follows:&lt;pre&gt;&lt;br /&gt;#define VISITED_CLASS(cls,parent) \&lt;br /&gt;  virtual bool enter(const cls &amp;amp;); \&lt;br /&gt;  virtual void exit(const cls &amp;amp;);&lt;br /&gt;#define VISITED_ABSTRACT_CLASS(cls, parent) \&lt;br /&gt;  VISITED_CLASS(cls,parent)&lt;br /&gt;#include "VisitorSpecs.hpp"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Remember, the "root" classes (those with no parent) are defined in terms of abstract classes.  So in fact, Visitor.hpp declares &lt;code&gt;enter()&lt;/code&gt; and &lt;code&gt;exit()&lt;/code&gt; for every visited class.&lt;br /&gt;&lt;br /&gt;Visitor.cpp defines default implementations for the member functions by defining the macros like this:&lt;pre&gt;&lt;br /&gt;// No parent default: don't recurse, do nothing.&lt;br /&gt;#define VISITED_ROOT_CLASS(cls) \&lt;br /&gt;bool Visitor::enter(const cls &amp;amp;) \&lt;br /&gt;{ \&lt;br /&gt;  VISITOR_CATCH_MISSING_HEADER(cls); \&lt;br /&gt;  return false; \&lt;br /&gt;} \&lt;br /&gt;void Visitor::exit(const cls &amp;amp;) \&lt;br /&gt;{ \&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Child classes: do what the parent would do.&lt;br /&gt;#define VISITED_CLASS(cls,parent) \&lt;br /&gt;bool Visitor::enter(const cls &amp;amp;c) \&lt;br /&gt;{ \&lt;br /&gt;  VISITOR_CATCH_MISSING_HEADER(cls); \&lt;br /&gt;  const parent &amp;amp;p = c; \&lt;br /&gt;  return enter(p); \&lt;br /&gt;} \&lt;br /&gt;void Visitor::exit(const cls &amp;amp;c) \&lt;br /&gt;{ \&lt;br /&gt;  const parent &amp;amp;p = c; \&lt;br /&gt;  exit(p); \&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Abstract classes: same as for concrete classes.&lt;br /&gt;#define VISITED_ABSTRACT_CLASS(cls, parent) \&lt;br /&gt;  VISITED_CLASS(cls,parent)&lt;br /&gt;&lt;br /&gt;#include "VisitorSpecs.hpp"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The macro definitions for Visitor.cpp implement the Default Visitor scheme: if a concrete Visitor doesn't define enter() for a given type, the default is picked up from the base class, and looks in the virtual table for the enter() belonging to the parent class.  We have Visitor.cpp include the header file VisitedClasses.hpp, which includes the .hpp for every concrete visited class.  Thus, when a new class is added to the hierarchy, Visitor.hpp and Visitor.cpp do not require any change whatsoever.&lt;br /&gt;&lt;br /&gt;Notice the lines in the function definitions that say &lt;code&gt;VISITOR_CATCH_MISSING_HEADER(cls)&lt;/code&gt;.  The reason for these lines, is that if you add a new class to the hierarchy, but forget to add an include to VisitedClasses.hpp, most compilers give you a confusing error message about initializing the variable &lt;code&gt;p&lt;/code&gt;.  On the versions of g++ and Solaris CC I've looked at, the message says nothing about an undefined class, let alone a missing header file.  So, in Visitor.cpp we define a macro which will give you an error message that points in the direction of the problem, if you have forgotten that include.  The macro is:&lt;pre&gt;&lt;br /&gt;#ifndef NDEBUG&lt;br /&gt;#define VISITOR_CATCH_MISSING_HEADER(cls) \&lt;br /&gt;  typedef cls INCLUDE_ ## cls ## \&lt;br /&gt;    _hpp_IN_VisitedClasses_hpp; \&lt;br /&gt;  struct Dummy : \&lt;br /&gt;    public INCLUDE_ ## cls ## \&lt;br /&gt;      _hpp_IN_VisitedClasses_hpp { \&lt;br /&gt;        Dummy(); \&lt;br /&gt;  }&lt;br /&gt;#else&lt;br /&gt;#define VISITOR_CATCH_MISSING_HEADER(cls) /* nothing */&lt;br /&gt;#endif&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We make the macro a no-op for non-debug builds, though it shouldn't really affect the code even if you enable it for release builds.  Compare the messages in g++ 4.1.2.  Suppose you omitted &lt;code&gt;#include "IfElse.hpp"&lt;/code&gt; from VisitedClasses.hpp.  Without the macro, the message says &lt;i&gt;VisitorSpecs.hpp:38: error: invalid initialization of reference of type 'const MultiStatement&amp;amp;' from expression of type 'const IfElse'&lt;/i&gt;; with the macro, you still get that message, but before it you get: &lt;i&gt;VisitorSpecs.hpp:38: error: invalid use of undefined type 'struct Visitor::enter(const IfElse&amp;amp;)::INCLUDE_IfElse_hpp_IN_VisitedClasses_hpp'&lt;/i&gt;.  A strange message, but it gets the point across better.&lt;br /&gt;&lt;br /&gt;Speaking of compiler errors, we will beef up the macro definitions in Visitor.hpp to catch a common coding error at compile time instead of having to debug strange behavior at runtime.  The issue is this: since the &lt;code&gt;enter()/exit()&lt;/code&gt; functions in our Visitor are not pure virtual, if you mistakenly add a concrete Visitor with one or more incorrect prototypes for those functions, the code will compile, link, and run -- silently skipping the functions with the incorrect prototypes, because the abstract base Visitor implementations will be found in the virtual table.&lt;br /&gt;&lt;br /&gt;For example, if your concrete Visitor declared &lt;code&gt;bool enter(const MultiStatement *)&lt;/code&gt; -- with a pointer argument instead of a reference -- then you wouldn't know anything was wrong until you ran the program.  In the worst case, you would not even notice that whatever behavior was supposed to happen in that MultiStatement &lt;code&gt;enter()&lt;/code&gt; didn't happen; even if you did notice it, you would have to step through in the debugger to watch the visit go into the wrong function.  To preclude some of the more common silent-but-deadly typos, we bulk up the Visitor.hpp macros like so:&lt;pre&gt;&lt;br /&gt;// The "real" prototypes.&lt;br /&gt;#define VISITED_CLASS_ENTER_EXIT(cls,parent) \&lt;br /&gt;  virtual bool enter(const cls &amp;amp;); \&lt;br /&gt;  virtual void exit(const cls &amp;amp;);&lt;br /&gt;&lt;br /&gt;// Fakes that turn typos into compile errors.&lt;br /&gt;#define FORBID_PTR_ARG(cls,parent) \&lt;br /&gt;  virtual _USE_REFERENCE_ARG *enter(const cls *) \&lt;br /&gt;    { return 0; } \&lt;br /&gt;  virtual _USE_REFERENCE_ARG *exit(const cls *) \&lt;br /&gt;    { return 0; }&lt;br /&gt;#define FORBID_NON_CONST_ARG(cls,parent) \&lt;br /&gt;  virtual _USE_CONST_REF *enter(cls &amp;amp;) \&lt;br /&gt;    { return 0; } \&lt;br /&gt;  virtual _USE_CONST_REF *exit(cls &amp;amp;) \&lt;br /&gt;    { return 0; }&lt;br /&gt;#define FORBID_CONST_FUNC(cls,parent) \&lt;br /&gt;  virtual _USE_NON_CONST_FUNC *enter(const cls &amp;amp;) \&lt;br /&gt;    const { return 0; } \&lt;br /&gt;  virtual _USE_NON_CONST_FUNC *exit(const cls &amp;amp;) \&lt;br /&gt;    const { return 0; }&lt;br /&gt;&lt;br /&gt;// Final macro definitions.&lt;br /&gt;#ifdef NDEBUG&lt;br /&gt;#define VISITED_CLASS(cls,parent) \&lt;br /&gt;  VISITED_CLASS_ENTER_EXIT(cls,parent)&lt;br /&gt;#else&lt;br /&gt;  class _USE_REFERENCE_ARG;&lt;br /&gt;  class _USE_CONST_REF;&lt;br /&gt;  class _USE_NON_CONST_FUNC;&lt;br /&gt;#define VISITED_CLASS(cls,parent) \&lt;br /&gt;  VISITED_CLASS_ENTER_EXIT(cls,parent) \&lt;br /&gt;  FORBID_PTR_ARG(cls,parent) \&lt;br /&gt;  FORBID_NON_CONST_ARG(cls,parent) \&lt;br /&gt;  FORBID_CONST_FUNC(cls,parent)&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;#define VISITED_ABSTRACT_CLASS(cls, parent) \&lt;br /&gt;  VISITED_CLASS(cls,parent)&lt;br /&gt;&lt;br /&gt;#include "VisitorSpecs.hpp"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Without the &lt;code&gt;FORBID*&lt;/code&gt; macros, the incorrect pointer-arg prototype above would prevent our FindLhsVars visitor in our previous &lt;a href="http://softwareengisneering.blogspot.com/2009/05/default-visitor-idiom.html"&gt;example&lt;/a&gt; from finding assigned-to variables in complex statements such as blocks or if-else statements.  With the macros in place, we get the following compile-time error: &lt;br /&gt;&lt;i&gt;VisitorSpecs.hpp:36: error:   overriding 'virtual Visitor::_USE_REFERENCE_ARG* Visitor::enter(const MultiStatement*)'&lt;/i&gt;.  That is &lt;span style="font-weight:bold;"&gt;money in the bank&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Are you still with me?  Then there's one more feature of this setup that I'd like to point out.  Notice that &lt;code&gt;VISITED_CLASS&lt;/code&gt; and its related macros can be defined in any file that includes VisitorSpecs.hpp.  As useful as Default Visitor is, there are some concrete Visitors that &lt;i&gt;must&lt;/i&gt; be updated whenever a new class is added to the hierarchy -- for example, the pretty-printer Visitor from the earlier &lt;a href="http://softwareengisneering.blogspot.com/2009/03/c-visitors-basic-implementation.html"&gt;post&lt;/a&gt;.  In that case, instead of hard-coding the &lt;code&gt;enter()&lt;/code&gt; function declarations in the concrete Visitor class definition, do this:&lt;pre&gt;&lt;br /&gt;#define VISITED_CLASS(cls,parent) \&lt;br /&gt;  virtual bool enter(const cls &amp;amp;);&lt;br /&gt;#include "VisitorSpecs.hpp"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, if you forget to define the enter function for a newly-added class, you will get a link error when the linker tries to build the virtual table.  From g++ 4.1.2: &lt;i&gt;Print.cpp:61: undefined reference to `Print::enter(IfElse const&amp;amp;)'&lt;/i&gt;.  Again, money in the bank.  You might also find that there is some boilerplate code you would like to generate for every visited class -- a thought that comes to mind is an enum representing class types in the hierarchy.  Simply extend the macro to include a third argument for that extra information -- if it can't be created with a '##' concatenation -- and include VisitorSpecs.hpp in the appropriate place.&lt;br /&gt;&lt;br /&gt;Whew!  This is a huge post, but when you apply these macro definitions to the improved Visitor in the earlier post, you have a very powerful idiom to work with.  I can see a couple more posts coming up in this series:  1. a listing of the final Statement, Expression, and Visitor code presented here (I've been compiling it as I wrote these posts, to make sure it all worked), and an example &lt;code&gt;main()&lt;/code&gt; to exercise it; and 2. discussion of a few Visitor issues I've glossed over to get this thing out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/837664636726682837-6145534857666444118?l=softwareengisneering.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=qbASeUK4w30:aQRfdYMxnrs:3QFJfmc7Om4"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=qbASeUK4w30:aQRfdYMxnrs:3QFJfmc7Om4" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=qbASeUK4w30:aQRfdYMxnrs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SoftwareEngisneering?a=qbASeUK4w30:aQRfdYMxnrs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SoftwareEngisneering?i=qbASeUK4w30:aQRfdYMxnrs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SoftwareEngisneering/~4/qbASeUK4w30" height="1" width="1"/&gt;</description><atom:updated xmlns:atom="http://www.w3.org/2005/Atom">2009-05-14T22:02:48.329-07:00</atom:updated><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://softwareengisneering.blogspot.com/2009/05/handy-c-visitor-macros.html</feedburner:origLink></item></channel></rss>

