<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5087326709910512917</id><updated>2012-01-26T11:23:57.290-06:00</updated><category term='linux'/><category term='ruby'/><category term='math'/><category term='theory'/><category term='active directory'/><category term='OpenAM'/><category term='emacs'/><category term='scala'/><category term='java'/><category term='authentication'/><category term='REST'/><category term='books'/><category term='vmware'/><category term='data structure'/><category term='comics'/><category term='random'/><category term='quote'/><category term='Dijkstra'/><category term='continuations'/><category term='notation'/><category term='lisp'/><category term='protocols'/><category term='conference'/><category term='http'/><category term='SAML'/><category term='tip'/><category term='electronics'/><category term='c'/><category term='software development'/><category term='yeti'/><category term='job'/><category term='osgi'/><category term='ldap'/><category term='coq'/><category term='shell'/><category term='unix'/><category term='haskell'/><category term='link'/><category term='eclipse virgo'/><category term='toy problems'/><category term='programming language'/><category term='c++'/><category term='naming'/><category term='Knuth'/><category term='system administration'/><title type='text'>Maniagnosis</title><subtitle type='html'>Not devoured by plague-bearing zombies!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default?start-index=101&amp;max-results=100'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>157</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-4275035349761887054</id><published>2012-01-25T22:56:00.000-06:00</published><updated>2012-01-25T22:56:00.231-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><category scheme='http://www.blogger.com/atom/ns#' term='random'/><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><title type='text'>Quote o' the week: a journal that meets in a hotel</title><content type='html'>&lt;p&gt;I reading my pile of magazines and ran across Moshe Vardi's "&lt;a href="http://cacm.acm.org/magazines/2011/9/122805-are-you-talking-to-me/fulltext"&gt;Are you talking to Me?&lt;/a&gt;" in the CACM. (It's a brilliant editorial; he mentions Doug Zongker's "&lt;a href="http://www.youtube.com/watch?v=yL_-1d9OSdk"&gt;Chicken Chicken Chicken&lt;/a&gt;" &lt;a href="http://isotropic.org/papers/chicken.ppt"&gt;talk&lt;/a&gt; (and &lt;a href="http://isotropic.org/papers/chicken.pdf"&gt;paper&lt;/a&gt;!), the number of people attending a conference who think presentations are an opportunity to check their email (yeah, I know most of the good stuff is in the "hall track"), and the following:&lt;/p&gt;&lt;blockquote&gt;I am reminded of Lance Fortnow's pithy description of a computer-science conference as "a journal that meets at a hotel."&lt;/blockquote&gt;&lt;p&gt;Unfortunately, Fortnow, who notably &lt;a href="http://people.cs.uchicago.edu/~fortnow/papers/growup.pdf"&gt;doesn't care for the state&lt;/a&gt; of computer science conferences, disclaims responsibility for the quote.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;How about this idea: We don't bother meeting and just collect the accepted papers into a single volume. We can give this idea an innovative name like a "journal".&lt;/p&gt;&lt;p&gt;In this month's CACM article, Moshe Vardi complains about the quality of conference talks. (I like the "journal  that meets in a hotel" quote but it didn't originate with me). You see this at STOC and FOCS too, people giving a talk only to other specialists in their field instead of aiming for a general audience.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Personally, I believe that the word "weasel" is inherently funny and deserves to be used much more often than it is.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-4275035349761887054?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/4275035349761887054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=4275035349761887054' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4275035349761887054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4275035349761887054'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2012/01/quote-o-week-journal-that-meets-in.html' title='Quote o&apos; the week: a journal that meets in a hotel'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-5884978790300772175</id><published>2012-01-22T14:25:00.000-06:00</published><updated>2012-01-22T14:27:07.404-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='toy problems'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='data structure'/><title type='text'>State space search: heuristics</title><content type='html'>&lt;p&gt;&lt;a href="http://maniagnosis.crsr.net/2012/01/state-space-search-basics.html"&gt;Last time&lt;/a&gt;, I wrote, without any explanation&lt;/p&gt;&lt;blockquote&gt;Using a FIFO queue searches the state space &lt;b&gt;breadth-first&lt;/b&gt;, visiting all of the states at a given distance from the initial state before any states at a greater distance. Using a LIFO queue searches the state space &lt;b&gt;depth-first&lt;/b&gt;, visiting all of the states following a given state before visiting any other states.&lt;/blockquote&gt;&lt;p&gt;The way that works is important to the power of search. Consider using a first-in, first-out queue and expanding an initial state \(n\). Expanding \(n\) enqueues the states \((o_1, o_2, o_3)\). The next step is to remove the first state from the queue, expand it, and enqueue the results, leaving the queue as \((o_2, o_3, p_1, p_2)\) (assuming expanding \(o_1\) produced \(p_1\) and \(p_2\)). As a result, following this queuing strategy, all of the states at depth \(o\) from the initial state are expanded before any of the states at depth \(p\). Hence, "breadth-first".&lt;/p&gt;&lt;p&gt;On the other hand, if the algorithm uses a last-in, first-out structure, expanding the same initial state \(n\) still produces a queue of \((o_1, o_2, o_3)\). However, the next step is to remove the &lt;em&gt;last&lt;/em&gt; state from the queue, expand it, and enqueue the results, producing \((o_1, o_2, p_1, p_2)\), assuming  expanding \(o_3\) produced \(p_1\) and \(p_2\) this time. This time, the &lt;em&gt;next&lt;/em&gt; step will be to expand \(p_2\), with the result that all of the states below \(o_3\) will be examined before any of the other states \(o_1\) or \(o_2\). Thus, "depth-first".&lt;/p&gt;&lt;p&gt;So far, I have been discussing &lt;b&gt;uninformed search&lt;/b&gt;; these approaches order their exploration of the problem's state space based on the pattern of state-space expansion. There is a better way: &lt;b&gt;informed search&lt;/b&gt; applies information about the problem to focus the exploration of the state space on &lt;em&gt;important&lt;/em&gt; regions. Here's an example:&lt;/p&gt;&lt;h2&gt;Sliding number puzzles: fifteenpuzzle&lt;/h2&gt;&lt;p&gt;Returning to &lt;a href="http://www.aiai.ed.ac.uk/~gwickler/eightpuzzle-inf.html"&gt;Gerhard Wickler&lt;/a&gt;, he describes the basics of the 8-puzzle (a smaller version of the 15-puzzle) as,&lt;/p&gt;&lt;img src="http://www.crsr.net/images/8puzzle.png" style="float:right; border:thin solid black; margin:10px" alt="Hideous illustration of an 8-puzzle"&gt;&lt;/img&gt;&lt;blockquote&gt;&lt;p&gt;The 8-puzzle is a smaller version of the slightly better known 15-puzzle. The puzzle consists of an area divided into a grid, 3 by 3 for the 8-puzzle, 4 by 4 for the 15-puzzle. On each grid square is a tile, expect for one square which remains empty. Thus, there are eight tiles in the 8-puzzle and 15 tiles in the 15-puzzle. A tile that is next to the empty grid square can be moved into the empty space, leaving its previous position empty in turn. Tiles are numbered, 1 thru 8 for the 8-puzzle, so that each tile can be uniquely identified.&lt;/p&gt;&lt;p&gt;The aim of the puzzle is to achieve a given configuration of tiles from a given (different) configuration by sliding the individual tiles around the grid as described above.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This puzzle is not hard to put into a form suitable for state space search, which should provide a solution as long as the algorithm does not expand a state more than once. If the shortest solution is needed, the breadth-first approach is a straightforward choice.&lt;/p&gt;&lt;p&gt;The state space for sliding puzzles is significantly larger than that of the missionaries and cannibals puzzle; there are \(n!\) ways to permute \(n\) tiles, although only half of those are reachable from a given goal state, although the proof is &lt;a href="http://en.wikipedia.org/wiki/Fifteen_puzzle"&gt;enlightening&lt;/a&gt; itself. (The 8-puzzle therefore illustrates one of the hazards of state space manipulation: some states may be unsolvable.) So, the 8-puzzle version has 181,440 possible states, including the empty tile; the 15-puzzle has 10,461,394,944,000.&lt;/p&gt;&lt;p&gt;As a result, a complete search of the state space is likely to be infeasible and any uninformed search will also likely take more resources than strictly desirable. But there are ways to exploit knowledge about the problem to shorten the search.&lt;/p&gt;&lt;p&gt;Suppose, for example, you can find out, given a state, approximately how many moves are needed to get from the state to a goal? Then, you could select the next state to explore based on your estimate of how close it is to the solution. Fortunately, both of these are possible: there are a number of &lt;b&gt;heuristics&lt;/b&gt; that can provide the necessary estimate, and our friend, the priority queue, can handle the selection of the next state to expand.&lt;/p&gt;&lt;p&gt;One possible heuristic is the number of out of place tiles, because that is obviously going to be related to the number of moves necessary to get the tiles into their places. Importantly, for reasons that I don't intend to go into here, it always &lt;em&gt;underestimates&lt;/em&gt; the number of moves. If the search explores the state space, focusing on the states with fewer and fewer tiles out of place, the search is likely to find the goal while significantly reducing the resources required.&lt;/p&gt;&lt;p&gt;To implement the states for the 15-puzzle, I chose to represent the positions of the tiles as locations in an &lt;code&gt;ArrayList&lt;/code&gt; of integers, with the tile values being 1 through 15 with 0 as the empty tile. (For expediency, I also record the location of the empty tile in the array.) As a result, determining whether a state is the goal is simple. For locations 0 to 14, whenever the value of the location is one greater than the location number, the puzzle is solved.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public boolean isGoal()&lt;br /&gt;  {&lt;br /&gt;    // The final square should be 0 but I don't care.&lt;br /&gt;    for (int i = 0; i &amp;lt; BOARD - 1; ++i)&lt;br /&gt;    {&lt;br /&gt;      if (board.get(i) != i + 1) { return false; }&lt;br /&gt;    }&lt;br /&gt;    return true;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Expanding a state a bit more complicated since it requires attempting to move the empty space left, right, up, and down. (Or, alternately, move the tile to the left into the empty space. Depends on how you look at these things.) One of the directional methods is shown below; the other three are similar.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public List&amp;lt;FState&gt; expand()&lt;br /&gt;  {&lt;br /&gt;    List&amp;lt;FState&gt; result = new ArrayList&amp;lt;FState&gt;();&lt;br /&gt;    for (FState newState : Arrays.asList(this.left(), this.right(), this.up(), this.down()))&lt;br /&gt;    {&lt;br /&gt;      if (newState != null) { result.add(newState); }&lt;br /&gt;    }&lt;br /&gt;    return result;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;[...]&lt;br /&gt;&lt;br /&gt;  private FState left()&lt;br /&gt;  {&lt;br /&gt;    if (empty % ROW != 0)&lt;br /&gt;    {&lt;br /&gt;      // Empty location is not at left edge&lt;br /&gt;      return new FState(this, empty - 1);&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;      return null;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;(I'll leave it to you to figure out how modular arithmatic lets me fiddle with a rectangular grid in a one-dimensional array.)&lt;/p&gt;&lt;p&gt;Implementing the out-of-position heuristic is similar to checking &lt;code&gt;isGoal&lt;/code&gt;, with the complication of counting the number of tiles out of place.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;  public int outOfPosition()&lt;br /&gt;  {&lt;br /&gt;    int out = 0;&lt;br /&gt;    for (int i = 0; i &amp;lt; BOARD - 1; ++i)&lt;br /&gt;    {&lt;br /&gt;      if (board.get(i) != i + 1)&lt;br /&gt;      {&lt;br /&gt;        ++out;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return out;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;And finally, to allow the heuristic function to interface with a priority queue, I need a &lt;code&gt;Comparator&lt;/code&gt; subclass.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;  public static class OutOfPosition implements Comparator&amp;lt;FState&gt;&lt;br /&gt;  {&lt;br /&gt;    @Override&lt;br /&gt;    public int compare(FState o1, FState o2)&lt;br /&gt;    {&lt;br /&gt;      return o1.outOfPosition() - o2.outOfPosition();&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The following code runs the search on a "harder" problem (harder than the one in the illustration above, anyway).&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;    System.out.println("Heuristic search: out of position");&lt;br /&gt;    Queue&lt;FState&gt; priority = new PriorityQueue&lt;FState&gt;(100, new FState.OutOfPosition());&lt;br /&gt;    Search&lt;FState&gt; search = new Search&lt;FState&gt;(queue, new HashSet&lt;FState&gt;(), FState.harder());&lt;br /&gt;    FState end = search.findGoal();&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This search exampines 4387 states to find a goal with a path length of 255.&lt;/p&gt;&lt;p&gt;There are certainly many possible heuristics. An alternative heuristic for the 15-puzzle is the total distance for each tile in a state between its position and its goal position. Specifically, the &lt;b&gt;Manhattan distance&lt;/b&gt;, which is sum of the number of rows and columns each tile is out of position. The total of the Manhattan distance is computed by the &lt;code&gt;totalDistance&lt;/code&gt; method. The advantage of this heuristic is that it more closely estimates the number of moves necessary to solve a puzzle from a given state.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;  public int totalDistance()&lt;br /&gt;  {&lt;br /&gt;    int out = 0;&lt;br /&gt;    for (int i = 0; i &amp;lt; BOARD; ++i)&lt;br /&gt;    {&lt;br /&gt;      if (i == empty) continue;&lt;br /&gt;      int position = board.get(i) - 1;&lt;br /&gt;      out += Math.abs((i % ROW) - (position % ROW));&lt;br /&gt;      out += Math.abs((i / ROW) - (position / ROW));&lt;br /&gt;    }&lt;br /&gt;    return out;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;In this case, rather than implementing &lt;code&gt;Comparator&lt;/code&gt;, I made the &lt;code&gt;FState&lt;/code&gt; class &lt;code&gt;Comparable&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public int compareTo(FState o)&lt;br /&gt;  {&lt;br /&gt;    return this.totalDistance() - o.totalDistance();&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The driver program creates a &lt;code&gt;PriorityQueue&lt;/code&gt; with no arguments to use the &lt;code&gt;Comparable&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;    System.out.println("Heuristic search: manhattan distance");&lt;br /&gt;    Queue&lt;FState&gt; priority = new PriorityQueue&lt;FState&gt;();&lt;br /&gt;    Search&lt;FState&gt; search = new Search&lt;FState&gt;(queue, new HashSet&lt;FState&gt;(), FState.harder());&lt;br /&gt;    FState end = search.findGoal();&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This version only examines 1469 states to find a solution of 205 moves.&lt;/p&gt;&lt;p&gt;For comparison, according to &lt;a href="http://en.wikipedia.org/wiki/Fifteen_puzzle"&gt;Wikipedia&lt;/a&gt;, "For the 15-puzzle, lengths of optimal solutions range from 0 to 80 moves". The difference is that the raw heuristic search that I am writing about here behaves similarly to depth-first search in that it makes no claim to find an optimal path. On the other hand, the raw heuristic search does find a solution quickly, much faster than a breadth-first search.&lt;/p&gt;&lt;p&gt;You can get the code on &lt;a href="https://github.com/tmmcguire/StateSpaceSearch"&gt;github &lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5884978790300772175?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/5884978790300772175/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5884978790300772175' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5884978790300772175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5884978790300772175'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2012/01/state-space-search-heuristics.html' title='State space search: heuristics'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-7219038370411770883</id><published>2012-01-15T22:37:00.000-06:00</published><updated>2012-01-22T14:26:16.530-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='toy problems'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='data structure'/><title type='text'>State space search: the basics</title><content type='html'>&lt;p&gt;A while back, briefly &lt;a href="http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for.html"&gt;discussing Steve McConnell's Code Complete&lt;/a&gt;, I wrote, "On the other hand, McConnell previously presented as a good use of recursion a maze-solving function; maze solving is an application of state-space search, which has a simple, clear, and wildly flexible iterative implementation based on a priority queue." Between that, and the Stanford AI course (which only briefly mentioned most of what I spent a semester learning back in the late '80's), I have been pondering state space search lately. It really is an elegant algorithm. So, I thought I'd spend some spare time writing an elaborate and likely unnecessary post or three about it.&lt;/p&gt;&lt;p&gt;I'll begin with a &lt;b&gt;state&lt;/b&gt;. A state is a particular configuration of the system in question. For example, a board position in chess is a state. When you place the pieces on the board, you create an &lt;b&gt;initial state&lt;/b&gt;; after some number of moves, the board is in some other state. When the game is over, the board is in a &lt;b&gt;terminal&lt;/b&gt; state; if you won, it's in a &lt;b&gt;goal&lt;/b&gt; state, but the difference is the topic of some other post. For the moment, I will only be talking about systems where the only terminal states are goals.&lt;/p&gt;&lt;p&gt;A &lt;b&gt;state space&lt;/b&gt; is the set of &lt;em&gt;all&lt;/em&gt; possible states for a system. For chess, the state space is &lt;em&gt;all&lt;/em&gt; possible board positions, and there are a lot of them. Chess has a fairly large state space. The states in a state space are related by the valid actions of the system; given a state those actions produce a collection of the next states reachable by one operation of the system. For chess, the actions are the valid moves of individual chess pieces and, because the initial state is defined by the rules of chess, the state space includes all board positions reachable from that initial state by legal chess moves.&lt;/p&gt;&lt;p&gt;&lt;b&gt;State space search&lt;/b&gt; is the technique of searching for a goal state, beginning with an initial state and using the operations available in each state to generate new states. Or, alternatively, beginning with a goal state and searching for a suitable initial state. Or possibly even starting with an initial state &lt;em&gt;and&lt;/em&gt; a goal state and searching for a way to connect the two in the state space. Each of those approaches is suitable for some problems, depending on the nature of the problem. The key point is to explore the state space of the problem, searching for a solution.&lt;/p&gt;&lt;p&gt;State space search is one of the most powerful techniques in computer science. If a problem can be framed in a way suitable to state space search (and most can), then the algorithm is guaranteed to find a solution. Theoretically, anyway. If you have a problem and do not have any more direct algorithm, it is the go-to way to solve it. Or, at least it was; there are other techniques that have become popular, usually for very good reasons.&lt;/p&gt;&lt;p&gt;On the other hand, state space search has some serious weaknesses. For one thing, not all problems can be usefully framed in terms of a state space. It requires that the problem be both discrete and deterministic; discrete in such a way that all states are distinct from one another and deterministic so that an action produces exactly one subsequent state from an input state. But that is not the worst part. State space search is the poster child for exponential algorithms. I said it was guaranteed to find a solution, but I carefully didn't say you would be alive to see it. Or, &lt;em&gt;anything&lt;/em&gt; would be alive to see it. But there are plenty of problems to which state space search is applicable.&lt;/p&gt;&lt;h2&gt;The algorithm&lt;/h2&gt;&lt;p&gt;So, with all that buildup, the algorithm is a typical let-down:&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;def search(queue):&lt;br /&gt;    while not empty?(queue):&lt;br /&gt;        current_state := remove_element(queue)&lt;br /&gt;        if is_goal?(current_state):&lt;br /&gt;            return current_state&lt;br /&gt;        for next_state in expand(current_state):&lt;br /&gt;            if not seen?(next_state):&lt;br /&gt;                mark_seen(next_state)&lt;br /&gt;                add(queue, next_state)&lt;br /&gt;    return nil&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The intelligence of the algorithm is actually in the:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Queue that is used to store states before they are examined and expanded and which determines the nature of the search,&lt;/li&gt;&lt;li&gt;The rules that determine whether a state is a goal and how the state is expanded into subsequent states, and&lt;/li&gt;&lt;li&gt;The set used to determine whether a state has been seen before; this and the queue will determine how much memory the algorithm uses.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;How does this look in Java?&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;  public T findGoal()&lt;br /&gt;  {&lt;br /&gt;    while (!queue.isEmpty())&lt;br /&gt;    {&lt;br /&gt;      statesExamined++;&lt;br /&gt;&lt;br /&gt;      T current = queue.remove();&lt;br /&gt;      if (current.isGoal())&lt;br /&gt;      {&lt;br /&gt;        return current;&lt;br /&gt;      }&lt;br /&gt;      for (T newState : current.expand())&lt;br /&gt;      {&lt;br /&gt;        if (!seen.contains(newState))&lt;br /&gt;        {&lt;br /&gt;          seen.add(newState);&lt;br /&gt;          queue.add(newState);&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return null;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;statesExamined&lt;/code&gt; is an accounting addition, just used for entertainment purposes. The rest of the class similarly simple, initializing &lt;code&gt;seen&lt;/code&gt; and &lt;code&gt;queue&lt;/code&gt; based on constructor arguments. Like I said, nothing up my sleeve....&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;public class Search&amp;lt;T extends State&amp;lt;T&gt;&gt;&lt;br /&gt;{&lt;br /&gt;  private int statesExamined;&lt;br /&gt;  private final Queue&amp;lt;T&gt; queue;&lt;br /&gt;  private final Set&amp;lt;T&gt; seen;&lt;br /&gt;&lt;br /&gt;  public Search(Queue&amp;lt;T&gt; queue, Set&amp;lt;T&gt; seen, T initialState)&lt;br /&gt;  {&lt;br /&gt;    this.queue = queue;&lt;br /&gt;    queue.add(initialState);&lt;br /&gt;    this.seen = seen;&lt;br /&gt;    this.statesExamined = 0;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  [...findGoal...]&lt;br /&gt;&lt;br /&gt;  public int statesExamined()&lt;br /&gt;  {&lt;br /&gt;    return statesExamined;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;Set&lt;/code&gt; &lt;code&gt;seen&lt;/code&gt; is used to prevent states from being expanded repeatedly. It records when a state is first seen and subsequently prevents it from being re-added to the queue. Without this, the algorithm could enter an infinite loop if the state space is not acyclic.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;State&lt;/code&gt; interface is not much more interesting. The only required methods are to expand the state, producing a list of subsequent states produced by valid actions, and a predicate that is true if the state is a goal.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;public interface State&lt;T&gt;&lt;br /&gt;{&lt;br /&gt;  public List&lt;T&gt; expand();&lt;br /&gt;&lt;br /&gt;  public boolean isGoal();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;If the state space search code is so simple, how is the algorithm capable of such power? How about an example?&lt;h2&gt;Missionaries and cannibals: rivercrossing&lt;/h2&gt;&lt;p&gt;The problem is, according to &lt;a href="http://www.aiai.ed.ac.uk/~gwickler/missionaries.html"&gt;Gerhard Wickler&lt;/a&gt;,&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;On one bank of a river are three missionaries and three cannibals. There is one boat available that can hold up to two people and that they would like to use to cross the river. If the cannibals ever outnumber the missionaries on either of the river’s banks, the missionaries will get eaten.&lt;/p&gt;&lt;p&gt;How can the boat be used to safely carry all the missionaries and cannibals across the river?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;(I have seen versions where the threat is the missionaries converting the cannibals, rather than the cannibals cannibalizing (ahem) the missionaries. I am a traditionalist, however.)&lt;/p&gt;&lt;a href="http://www.aiai.ed.ac.uk/~gwickler/missionaries.html"&gt;&lt;img style="background-color: white; padding:5px; margin:10px; border:medium solid black; float:right;" src="http://www.aiai.ed.ac.uk/~gwickler/images/mc-search-space.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;p&gt;Gerhard Wickler also has an excellent illustration of the complete state space for this problem. The initial state is on the left; the goal state is on the right. With 16 states, the state space is &lt;em&gt;tiny&lt;/em&gt; in comparison with the space of other problems, but it gets my point across.&lt;/p&gt;&lt;p&gt;Each state is a configuration of the missionaries and cannibals on each side of the river as well as which shore the boat is on. The process of crossing the river is abstracted away; each state transition involves the boat, with at least one passenger, crossing the river.&lt;/p&gt;&lt;p&gt;Specifically, a state in the puzzle is made up of the participants on this side of the river, the participants on that side of the river, and the location of the boat, this side or that side.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;  private static enum BoatSide { THIS, THAT };&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;On either side of the river are some number of missionaries and cannibals. I abstracted out the state of each side of the river as a class. There are a couple of special features of &lt;code&gt;RiverSide&lt;/code&gt;, though.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;First, the class includes methods &lt;code&gt;missionaries&lt;/code&gt;, &lt;code&gt;cannibals&lt;/code&gt;, and &lt;code&gt;both&lt;/code&gt; which returns a new &lt;code&gt;RiverSide&lt;/code&gt; instance with the number of missionaries or cannibals modified. These are used when generating new states while expanding a given state.&lt;/li&gt;&lt;li&gt;Second, the class implements &lt;code&gt;equals&lt;/code&gt; and &lt;code&gt;hashCode&lt;/code&gt;, making instances eligible to be stored in a &lt;code&gt;HashMap&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;br /&gt;  private static class RiverSide&lt;br /&gt;  {&lt;br /&gt;    public final int missionaries;&lt;br /&gt;    public final int cannibals;&lt;br /&gt;    &lt;br /&gt;    public RiverSide(int missionaries, int cannibals)&lt;br /&gt;    {&lt;br /&gt;      this.missionaries = missionaries;&lt;br /&gt;      this.cannibals = cannibals;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public RiverSide missionaries(int n)&lt;br /&gt;    {&lt;br /&gt;      return new RiverSide(missionaries + n, cannibals);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public RiverSide cannibals(int n)&lt;br /&gt;    {&lt;br /&gt;      return new RiverSide(missionaries, cannibals + n);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public RiverSide both(int n)&lt;br /&gt;    {&lt;br /&gt;      return new RiverSide(missionaries + n, cannibals + n);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    public boolean equals(Object o)&lt;br /&gt;    {&lt;br /&gt;      if (! (o instanceof RiverSide)) return false;&lt;br /&gt;      final RiverSide other = (RiverSide) o;&lt;br /&gt;      return this.missionaries == other.missionaries&lt;br /&gt;          &amp;&amp; this.cannibals == other.cannibals;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    public int hashCode()&lt;br /&gt;    {&lt;br /&gt;      return missionaries ^ cannibals;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    public String toString()&lt;br /&gt;    {&lt;br /&gt;      return String.format("[%d missionaries, %d cannibals]", missionaries, cannibals);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;There are two constructors for the state class: the first, public, one creates the initial state for the problem, with three missionaries, three cannibals, and the boat on this side of the river. The second, private, one creates a new &lt;code&gt;MCState&lt;/code&gt; based on a previous one and updated inhabitants of this and that side. The previous state is recorded so that the program can reconstruct the sequences of moves in a solution.&lt;/p&gt;&lt;p&gt;The methods required for &lt;code&gt;State&lt;/code&gt; are next. &lt;code&gt;isGoal&lt;/code&gt; is implemented by checking how many missionaries and cannibals are on that side of the river. &lt;code&gt;expand&lt;/code&gt; is more complex, but breaks down into a number of branches; if the boat is on this side of the river, then &lt;code&gt;expand&lt;/code&gt; generates all possible ways for it to get to the other side of the river, carrying one or two missionaries or cannibals; if the boat is on the other side, it does the reverse. Specifically, it collects a list of subsequent states; if at least one missionary is on this side, then a possible next state has the boat and one more missionary on that side. Likewise, if there are two missionaries on this side with the boat, another next state would be two less missionaries on this side and two more and the boat on that. The same logic applies to the cannibals and to a missionary and a cannibal moving to the other side. All of these branches go through &lt;code&gt;queueNewState&lt;/code&gt;, which first checks whether the new state is invalid if it presents the opportunity for some cannibals to devour some missionaries. As a result of the branches, each state has five possible next states, although some (or most) of those states are invalid.&lt;/p&gt;&lt;p&gt;&lt;code&gt;MCState&lt;/code&gt; also implements &lt;code&gt;hashCode&lt;/code&gt; and &lt;code&gt;equals&lt;/code&gt;, making instances eligible for &lt;code&gt;HashSet&lt;/code&gt; storage.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;public class MCState implements State&amp;lt;MCState&gt;&lt;br /&gt;{&lt;br /&gt;  [...]&lt;br /&gt;  &lt;br /&gt;  public final BoatSide boatSide;&lt;br /&gt;  public final RiverSide thisSide;&lt;br /&gt;  public final RiverSide thatSide;&lt;br /&gt;  public final MCState previous;&lt;br /&gt;  &lt;br /&gt;  public MCState()&lt;br /&gt;  {&lt;br /&gt;    boatSide = BoatSide.THIS;&lt;br /&gt;    thisSide = new RiverSide(3, 3);&lt;br /&gt;    thatSide = new RiverSide(0, 0);&lt;br /&gt;    previous = null;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  private MCState(MCState previous, RiverSide thisSide, RiverSide thatSide)&lt;br /&gt;  {&lt;br /&gt;    this.boatSide = previous.boatSide == BoatSide.THIS ? BoatSide.THAT : BoatSide.THIS;&lt;br /&gt;    this.thisSide = thisSide;&lt;br /&gt;    this.thatSide = thatSide;&lt;br /&gt;    this.previous = previous;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  @Override&lt;br /&gt;  public boolean isGoal()&lt;br /&gt;  {&lt;br /&gt;    return thatSide.missionaries == 3 &amp;&amp; thatSide.cannibals == 3;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public List&amp;lt;MCState&gt; expand()&lt;br /&gt;  {&lt;br /&gt;    List&amp;lt;MCState&gt; newStates = new ArrayList&amp;lt;MCState&gt;();&lt;br /&gt;    if (boatSide == BoatSide.THIS)&lt;br /&gt;    {&lt;br /&gt;      if (thisSide.missionaries &gt; 0)&lt;br /&gt;      {&lt;br /&gt;        final MCState newState =&lt;br /&gt;            new MCState(this, thisSide.missionaries(-1), thatSide.missionaries(1));&lt;br /&gt;        queueNewState(newStates, newState);&lt;br /&gt;      }&lt;br /&gt;      if (thisSide.missionaries &gt; 1)&lt;br /&gt;      {&lt;br /&gt;        final MCState newState =&lt;br /&gt;            new MCState(this, thisSide.missionaries(-2), thatSide.missionaries(2));&lt;br /&gt;        queueNewState(newStates, newState);&lt;br /&gt;      }&lt;br /&gt;      if (thisSide.cannibals &gt; 0)&lt;br /&gt;      {&lt;br /&gt;        final MCState newState =&lt;br /&gt;            new MCState(this, thisSide.cannibals(-1), thatSide.cannibals(1));&lt;br /&gt;        queueNewState(newStates, newState);&lt;br /&gt;      }&lt;br /&gt;      if (thisSide.cannibals &gt; 1)&lt;br /&gt;      {&lt;br /&gt;        final MCState newState =&lt;br /&gt;            new MCState(this, thisSide.cannibals(-2), thatSide.cannibals(2));&lt;br /&gt;        queueNewState(newStates, newState);&lt;br /&gt;      }&lt;br /&gt;      if (thisSide.missionaries &gt; 0 &amp;&amp; thisSide.cannibals &gt; 0)&lt;br /&gt;      {&lt;br /&gt;        final MCState newState =&lt;br /&gt;            new MCState(this, thisSide.both(-1), thatSide.both(1));&lt;br /&gt;        queueNewState(newStates, newState);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;      if (thatSide.missionaries &gt; 0)&lt;br /&gt;      {&lt;br /&gt;        final MCState newState =&lt;br /&gt;            new MCState(this,thisSide.missionaries(1), thatSide.missionaries(-1));&lt;br /&gt;        queueNewState(newStates, newState);&lt;br /&gt;      }&lt;br /&gt;      if (thatSide.missionaries &gt; 1)&lt;br /&gt;      {&lt;br /&gt;        final MCState newState =&lt;br /&gt;            new MCState(this,thisSide.missionaries(2), thatSide.missionaries(-2));&lt;br /&gt;        queueNewState(newStates, newState);&lt;br /&gt;      }&lt;br /&gt;      if (thatSide.cannibals &gt; 0)&lt;br /&gt;      {&lt;br /&gt;        final MCState newState =&lt;br /&gt;            new MCState(this,thisSide.cannibals(1), thatSide.cannibals(-1));&lt;br /&gt;        queueNewState(newStates, newState);&lt;br /&gt;      }&lt;br /&gt;      if (thatSide.cannibals &gt; 1)&lt;br /&gt;      {&lt;br /&gt;        final MCState newState =&lt;br /&gt;            new MCState(this,thisSide.cannibals(2), thatSide.cannibals(-2));&lt;br /&gt;        queueNewState(newStates, newState);&lt;br /&gt;      }&lt;br /&gt;      if (thatSide.missionaries &gt; 0 &amp;&amp; thatSide.cannibals &gt; 0)&lt;br /&gt;      {&lt;br /&gt;        final MCState newState =&lt;br /&gt;            new MCState(this,thisSide.both(1), thatSide.both(-1));&lt;br /&gt;        queueNewState(newStates, newState);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return newStates;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  private void queueNewState(final List&lt;MCState&gt; newStates, final MCState newState)&lt;br /&gt;  {&lt;br /&gt;    if (newState.isValid())&lt;br /&gt;    {&lt;br /&gt;      newStates.add(newState);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  private boolean isValid()&lt;br /&gt;  {&lt;br /&gt;    return (thisSide.missionaries == 0 || thisSide.missionaries &gt;= thisSide.cannibals)&lt;br /&gt;        &amp;&amp; (thatSide.missionaries == 0 || thatSide.missionaries &gt;= thatSide.cannibals);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public String toString()&lt;br /&gt;  {&lt;br /&gt;    final String format = (boatSide == BoatSide.THIS) ? "%s * -&gt; %s" : "%s -&gt; * %s";&lt;br /&gt;    return String.format(format, thisSide, thatSide);&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  @Override&lt;br /&gt;  public boolean equals(final Object o)&lt;br /&gt;  {&lt;br /&gt;    if (! (o instanceof MCState)) return false;&lt;br /&gt;    final MCState other = (MCState) o;&lt;br /&gt;    return this.thisSide.equals(other.thisSide)&lt;br /&gt;        &amp;&amp; this.thatSide.equals(other.thatSide)&lt;br /&gt;        &amp;&amp; this.boatSide == other.boatSide;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  @Override&lt;br /&gt;  public int hashCode()&lt;br /&gt;  {&lt;br /&gt;    return thisSide.hashCode() ^ thatSide.hashCode() ^ boatSide.hashCode();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;That is a fair amount of code, and nicely tedious. The key points, though, are the implementation of the &lt;code&gt;State&lt;/code&gt; interface; the State knows whether or not it is a goal, and it knows how to generate the &lt;em&gt;next&lt;/em&gt; states, following immediate, single step actions.&lt;/p&gt;&lt;p&gt;After that big wall o' code, you are probably waiting for a punch line. Unfortunately, there isn't one. Just a driver class invoking the search twice with a couple of different queue parameters. The first option uses &lt;code&gt;ArrayDeque&lt;/code&gt;, which implements a First-In, First-Out queue.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;    Queue&lt;MCState&gt; fifo = new ArrayDeque&lt;MCState&gt;();&lt;br /&gt;    Search&lt;MCState&gt; search = new Search&lt;MCState&gt;(fifo, new HashSet&lt;MCState&gt;(), new MCState());&lt;br /&gt;    MCState end = search.findGoal();&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The second option uses an anonymous subclass of &lt;code&gt;ArrayDequeue&lt;/code&gt; where &lt;code&gt;remove&lt;/code&gt; calls &lt;code&gt;removeLast&lt;/code&gt; rather than &lt;code&gt;removeFirst&lt;/code&gt;. As a result, it implements a Last-In, First-Out queue, or a stack.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;    Queue&lt;MCState&gt; lifo = new ArrayDeque&lt;MCState&gt;() {&lt;br /&gt;&lt;br /&gt;      @Override&lt;br /&gt;      public MCState remove()&lt;br /&gt;      {&lt;br /&gt;        return super.removeLast();&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;    };&lt;br /&gt;    Search&lt;MCState&gt; search = new Search&lt;MCState&gt;(lifo, new HashSet&lt;MCState&gt;(), new MCState());&lt;br /&gt;    MCState end = search.findGoal();&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;These two options are my first demonstration of the flexibility of the state space search algorithm. Using a FIFO queue searches the state space breadth-first, visiting all of the states at a given distance from the initial state before any states at a greater distance. Using a LIFO queue searches the state space depth-first, visiting all of the states following a given state before visiting any other states. The difference in this case is modest; a FIFO queue visits 16 states while a LIFO queue visits 13 to find a solution. But that is just the tip of the iceberg.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Update: completely forgot about this.&lt;/em&gt; If you want to try it yourself, there is a related problem involving a farmer crossing a river. The farmer is carrying a bushel of corn, a duck, and a fox. (Yeah, I don't really get it either.) If the duck is left unattended with the corn, the corn gets eaten. If the fox is left unattended with the duck, the duck gets eaten. The boat will only carry the farmer and one of the other items. How can the farmer get to the other side of the river with the corn, duck, and fox intact? You can get the state space search code, such as it is, and you will need to write a &lt;code&gt;State&lt;/code&gt; for the problem similar to &lt;code&gt;MCState&lt;/code&gt; and a driver program.&lt;/p&gt;&lt;p&gt;For the continuing story of state space search, check out the next post, &lt;a href="http://maniagnosis.crsr.net/2012/01/state-space-search-heuristics.html"&gt;State space search: heuristics&lt;/a&gt;.&lt;p&gt;You can get the code on &lt;a href="https://github.com/tmmcguire/StateSpaceSearch"&gt;github&lt;/a&gt;. I owe a considerable debt to Gerhard Wickler for his problem definition and illustration. He has a &lt;a href="http://www.aiai.ed.ac.uk/~gwickler/java/classes/ai.search.jar"&gt;Java library&lt;/a&gt; of &lt;a href="http://www.aiai.ed.ac.uk/~gwickler/java/doc/ai.search/"&gt;documented search code&lt;/a&gt; that you might want to check out as well.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-7219038370411770883?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/7219038370411770883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=7219038370411770883' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7219038370411770883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7219038370411770883'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2012/01/state-space-search-basics.html' title='State space search: the basics'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-7447222538529331152</id><published>2012-01-11T15:30:00.001-06:00</published><updated>2012-01-11T15:31:07.828-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='system administration'/><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><title type='text'>Quote o' the week: I've got my skillet right here, buddy</title><content type='html'>&lt;p&gt;Perusing some &lt;a href="http://imgur.com/CCCcw"&gt;cable-porn&lt;/a&gt; on &lt;a href="http://www.reddit.com/r/sysadmin"&gt;/r/sysadmin&lt;/a&gt;, I found this piece of wisdom:&lt;/p&gt;&lt;blockquote&gt;It's a two-pronged issue: Developers don't usually have the skillets or interests required for system administration.&lt;/blockquote&gt;&lt;p&gt;That was part of a couple of insightful posts by sylver_dragon and tuba_man about the costs of using developers instead of sysadmins for system administration.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.reddit.com/r/sysadmin/comments/obazt/so_i_went_in_to_a_new_client_to_patch_in_a_few/c3g5dm0"&gt;sylver_dragon&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&gt; Developers are not sysadmins&lt;/p&gt;&lt;p&gt;This is one of my biggest complaints about the blanket term "IT". I have dealt with too many managers who don't understand that there really is (or should be) a separation between Systems Administration and Software Development. Usually, you get a developer acting as admin when either role is (at least) a full time job. The end result is usually that the little things on the sysadmin side suffer. Cable routing is treated as, "fuck it, good enough." Documentation is usually not maintained, regular log checking doesn't happen, etc. It's not that the developer can't do it, it's just that he doesn't have time.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;a href="http://www.reddit.com/r/sysadmin/comments/obazt/so_i_went_in_to_a_new_client_to_patch_in_a_few/c3g5ked"&gt;tuba_man&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Exactly. Not only does he not have the time, but in a lot of ways, it prevents the developer (and the project or company as a whole) from operating most effectively. It's a two-pronged issue: Developers don't usually have the skillets or interests required for system administration. Application developers can work a lot better when they have solid systems to code on and deploy to. So a developer doing sysadmin work solely because he has to is in many cases shooting himself in the foot.&lt;/p&gt;&lt;p&gt;In my instance at least, our company's two developers work a hell of a lot better when they don't have to worry about systems or infrastructure. Since hiring me on, we've had more code output, higher quality code output, more uptime, better response times, and less customer complaints.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I, personally, keep my skillet with me at all times.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-7447222538529331152?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/7447222538529331152/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=7447222538529331152' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7447222538529331152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7447222538529331152'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2012/01/quote-o-week-ive-got-my-skillet-right.html' title='Quote o&apos; the week: I&apos;ve got my skillet right here, buddy'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-4180702227215630485</id><published>2012-01-04T20:07:00.000-06:00</published><updated>2012-01-04T20:07:00.653-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='link'/><title type='text'>Update to "System programming"</title><content type='html'>&lt;p&gt;In case anyone is interested, I added a brief discussion of Jonathan Shapiro's "Programming Language Challenges in Systems Codes: Why Systems Programmers Still Use C, and What to Do About It" to &lt;a href="http://maniagnosis.crsr.net/2011/11/systems-programming.html"&gt;Systems programming&lt;/a&gt;. He has an interesting definition of systems programs, and significant insights into the requirements for a systems programming language.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-4180702227215630485?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/4180702227215630485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=4180702227215630485' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4180702227215630485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4180702227215630485'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2012/01/update-to-system-programming.html' title='Update to &quot;System programming&quot;'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-3091123675978638769</id><published>2011-12-30T18:25:00.001-06:00</published><updated>2011-12-30T18:25:17.907-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='system administration'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='tip'/><title type='text'>Tip: Converting a CVS repository to git</title><content type='html'>&lt;p&gt;I have a great load of source code (and other detritus) in a CVS repository that I've been copying around for years. I have not used CVS for anything new in a very long time, but because I was the only one modifying things, I did not bother to move the contents to anything more modern.&lt;/p&gt;&lt;p&gt;Occasionally, I need to reactivate a project, and usually want to move the history into a newer tool, git usually. And every time, I have to look up how to do it. So, here's the latest working scheme, in hopes that I don't have to search around anymore.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Copy the CVSROOT directory and the module from the repository to someplace local. My CVS root (and the master git repositories) live remotely. The destination doesn't matter much.&lt;/p&gt;&lt;pre&gt;scp -r remote:CVS/{CVSROOT,module} CVS&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Get a copy of the latest &lt;a href="http://cvs2svn.tigris.org/servlets/ProjectDocumentList"&gt;cvs2svn&lt;/a&gt;, which includes &lt;a href="http://cvs2svn.tigris.org/cvs2git.html"&gt;cvs2git&lt;/a&gt;, which seems to be working better than I remember. Use cvs2git to create the two git fast-import format files from the repository.&lt;/p&gt;&lt;pre&gt;cvs2svn-2.3.0/cvs2git --blobfile=module-blob.dat --dumpfile=module-dump.dat --username me CVS/&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Create a new git repository to act as the master repository for the project.&lt;/p&gt;&lt;pre&gt;mkdir module.git&lt;br /&gt;cd module.git/&lt;br /&gt;git init --bare --shared&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Import the project.&lt;/p&gt;&lt;pre&gt;cat ../module-blob.dat ../module-dump.dat | git fast-import&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Put the new master repository back on my remote server.&lt;/p&gt;&lt;pre&gt;cd ..; scp -r module.git remote:GIT/&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Clone the remote repository to create a local, working repository.&lt;/p&gt;&lt;pre&gt;git clone ssh://remote/home/me/GIT/module.git&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The import above leaves the CVSROOT and module directories in the git repository, so the useful content of the module is one level down into the repository. The first git operation on the working repository fixes that.&lt;/p&gt;&lt;pre&gt;git rm -r CVSROOT/&lt;br /&gt;git mv module/* .&lt;br /&gt;git rm -r module&lt;br /&gt;git commit -m 'Removing cvs residue'&lt;br /&gt;git push&lt;/pre&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;And with luck, that's that.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3091123675978638769?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/3091123675978638769/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3091123675978638769' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3091123675978638769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3091123675978638769'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/12/tip-converting-cvs-repository-to-git.html' title='Tip: Converting a CVS repository to git'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-1085552593846090461</id><published>2011-12-24T09:52:00.001-06:00</published><updated>2011-12-24T09:53:12.735-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>Quote o' the day: Criticism</title><content type='html'>&lt;p&gt;From &lt;a href="http://www.reddit.com/r/programming/comments/no8o8/five_things_roger_ebert_taught_me_about/c3ancbb"&gt;reddit:&lt;/a&gt;&lt;/p&gt;&lt;blockquote&gt;Criticizing another's favorite language is like criticizing their genitalia, religion or politics.&lt;/blockquote&gt;&lt;p&gt;Words to live by.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-1085552593846090461?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/1085552593846090461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1085552593846090461' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1085552593846090461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1085552593846090461'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/12/quote-o-day-criticism.html' title='Quote o&apos; the day: Criticism'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-6774262489128725670</id><published>2011-12-15T20:30:00.000-06:00</published><updated>2011-12-16T11:41:37.426-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='comics'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='link'/><title type='text'>Link o' the day: Set Theory</title><content type='html'>&lt;p&gt;I never really understood the whole deal about the &lt;a href="http://www.math.vanderbilt.edu/~schectex/ccc/choice.html"&gt;Axiom of Choice&lt;/a&gt;. ("the last great controversy of mathematics"?) But now, I get it. Thanks, Randall Munroe!&lt;/p&gt;&lt;a href="http://xkcd.com/982/"&gt;&lt;img width="255px" height=354px" src="http://imgs.xkcd.com/comics/set_theory.png" title="Proof of Zermelo&amp;#39;s well-ordering theorem given the Axiom of Choice: 1: Take S to be any set. 2: When I reach step three, if S hasn&amp;#39;t managed to find a well-ordering relation for itself, I&amp;#39;ll feed it into this wood chipper. 3: Hey, look, S is well-ordered."&gt;&lt;/img&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-6774262489128725670?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/6774262489128725670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=6774262489128725670' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6774262489128725670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6774262489128725670'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/12/link-o-day-set-theory.html' title='Link o&apos; the day: Set Theory'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-5510162608062931828</id><published>2011-12-12T06:00:00.000-06:00</published><updated>2011-12-16T11:44:12.163-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='toy problems'/><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='notation'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>Mad science, abstract data types, and objects</title><content type='html'>&lt;p&gt;Mad science, and mad scientists, are always good to find. They represent guaranteed entertainment. But they do show up in the &lt;i&gt;oddest&lt;/i&gt; places. How about this one: OOPSLA 2009, William Cook presents a talk entitled "No one listened! But I'll show them, I'll show them all!". And the weird part was, nobody noticed. Well, sure, it's actually a popular paper that gets referenced frequently and the title is really "&lt;a href="http://dl.acm.org/authorize?148131"&gt;On Understanding Data Abstraction, Revisited&lt;/a&gt;", but there's no real sign that the peasants went scurrying for their pitchforks and torches.&lt;/p&gt;&lt;div style="float:right; margin:20px;"&gt;&lt;img style="border:thick solid black;" src="http://www.crsr.net/images/will_cook2003.jpg"&gt;&lt;/img&gt;&lt;p style="text-align:center;"&gt;&lt;b&gt;William Cook&lt;/b&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;So, what's the deal with Cook and his paper?&lt;/p&gt;&lt;h2&gt;A little backstory&lt;/h2&gt;&lt;p&gt;In 1990, Cook published "&lt;a href="http://www.cs.utexas.edu/~wcook/papers/OOPvsADT/CookOOPvsADT90.pdf"&gt;Object-Oriented Programming Versus Abstract Data Types&lt;/a&gt;" which is almost identical in content to, but somewhat longer than, "On Understanding Data Abstraction, Revisited". In both papers Cook describes the long-established, but little known, difference between &lt;i&gt;objects&lt;/i&gt; and &lt;i&gt;abstract data types&lt;/i&gt;. (For simplicity, the object-oriented side is limited to a subset of what I learned to call "object-based programming"; objects, as you might normally think of them, minus inheritance and also without modifications.)&lt;/p&gt;&lt;p&gt;Given those limitations, objects are data abstractions that "have a collection of methods, or procedures, that share access to private local state." Consider the type specimen of object-oriented programming: Smalltalk. In Smalltalk, objects have internal fields that contain the object's state, but this state is entirely unavailable to the outside world. Instead the object has a collection of messages that it responds to, exposing information potentially based on its internal state as necessary. Once an object is created, it is entirely encapsulated, isolated from any other code than that implementing its behavior. Because the interface of the data abstraction is the methods exposed by the object, Cook identifies objects as &lt;i&gt;procedural data abstractions&lt;/i&gt;. The key feature of an object is that its interface is defined by its constructor: the collection of methods the object responds to and the semantics of those methods are defined by the construction of the object. In a sense, those methods are associated with the specific &lt;i&gt;value&lt;/i&gt; or instance.&lt;/p&gt;&lt;p&gt;Abstract data types, on the other hand, have "a public name, a hidden representation, and operations to create, combine, and observe values of the abstraction." The classic examples of them are the primitive types in Java, C++, or most other common languages. A value has a defined type name, say "double", &lt;i&gt;some&lt;/i&gt; representation (Do you really know, or care, what a double actually looks like? (&lt;i&gt;Note:&lt;/i&gt; You &lt;i&gt;should&lt;/i&gt;. Floating point numbers are a notoriously leaky abstraction.)), and operations like reading one or converting one from some other representation, adding or subtracting two of them, and converting one to another representation, such as a string of characters. The key feature of an ADT is that its interface is defined by a collection of operations that apply to a specific &lt;i&gt;type.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;table style="text-align:center; float:left;margin:10px;"&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;th colspan="2"&gt;Constructors&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;Observations&lt;/th&gt;&lt;th&gt;[]&lt;/th&gt;&lt;th&gt;::&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;empty?&lt;/th&gt;&lt;td&gt;true&lt;/td&gt;&lt;td&gt;false&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;head&lt;/th&gt;&lt;td&gt;error&lt;/td&gt;&lt;td&gt;value&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;Let's say we create a matrix of operations on a data abstraction. My data abstraction is a list; it has two constructors, the Haskell-like "[]", or nil, building an empty list, and "::" or "cons", representing a constructor that takes a new element and an existing list and produces a new, combined list with the new element at the head. The list also has two "observation" operations, &lt;b&gt;empty?&lt;/b&gt; which returns true for an empty list and false otherwise, and &lt;b&gt;head&lt;/b&gt;, which produces some kind of error on an empty list, but returns the first value in the list otherwise. (This example is taken directly from "OOP Versus ADT".)&lt;/p&gt;&lt;div style="float:right; margin:10px;"&gt;&lt;table style="text-align:center;"&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;th colspan="2"&gt;Constructors&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;Observations&lt;/th&gt;&lt;th style="border-top:thin solid black;border-left:thin solid black;border-right:thin solid black"&gt;[]&lt;/th&gt;&lt;th style="border-top:thin solid black;border-left:thin solid black;border-right:thin solid black"&gt;::&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;empty?&lt;/th&gt;&lt;td style="border-left:thin solid black;border-right:thin solid black"&gt;true&lt;/td&gt;&lt;td style="border-left:thin solid black;border-right:thin solid black"&gt;false&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;head&lt;/th&gt;&lt;td style="border-bottom:thin solid black;border-left:thin solid black;border-right:thin solid black"&gt;error&lt;/td&gt;&lt;td style="border-bottom:thin solid black;border-left:thin solid black;border-right:thin solid black"&gt;value&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p style="text-align:center;"&gt;Object-oriented&lt;/p&gt;&lt;/div&gt;&lt;p&gt;Suppose I want to create an object-oriented version of this data abstraction. I would divide up the operations by constructor, so that I had an implementation of &lt;b&gt;empty?&lt;/b&gt; and &lt;b&gt;head&lt;/b&gt; for an empty list and &lt;b&gt;empty?&lt;/b&gt; and &lt;b&gt;head&lt;/b&gt; for a cons cell. The details of each operation is divided among the objects created by each specific constructor. Adding a new constructor is easy, since it simply requires providing implementations of the observations on the new object. On the other hand, adding a new observation is difficult, since it requires modifying all of the existing constructors. This should sound familiar to anyone who has written code in almost any object oriented language.&lt;/p&gt;&lt;div style="float:left;margin:10px;"&gt;&lt;table style="text-align:center;"&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;th colspan="2"&gt;Constructors&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;Observations&lt;/th&gt;&lt;th&gt;[]&lt;/th&gt;&lt;th&gt;::&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th style="border-top:thin solid black;border-left:thin solid black; border-bottom:thin solid black;"&gt;empty?&lt;/th&gt;&lt;td style="border-top:thin solid black;border-bottom:thin solid black;"&gt;true&lt;/td&gt;&lt;td style="border-top:thin solid black;border-right:thin solid black; border-bottom:thin solid black;"&gt;false&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th style="border-top:thin solid black;border-left:thin solid black; border-bottom:thin solid black;"&gt;head&lt;/th&gt;&lt;td style="border-top:thin solid black;border-bottom:thin solid black;"&gt;error&lt;/td&gt;&lt;td style="border-top:thin solid black;border-right:thin solid black; border-bottom:thin solid black;"&gt;value&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p style="text-align:center;"&gt;ADT&lt;/p&gt;&lt;/div&gt;&lt;p&gt;On the other hand, suppose I want an ADT version of this data abstraction. In this case, I would divide the operations by observation, so that I had an implementation of &lt;b&gt;empty?&lt;/b&gt; and &lt;b&gt;head&lt;/b&gt; that each covered all of the constructors. The details of each constructor is spread among the observation implementations. Adding new observation is easy; it just has to handle the individual cases of the constructors. Adding a new constructor is hard, though, because every observation needs to be modified. This option should be familiar to anyone who has used ML or Haskell, since it is how their algebraic data types work.&lt;/p&gt;&lt;p&gt;There are some less obvious consequences to these two styles of data abstraction. For one thing, the two approaches are almost duals; the advantages of one are the weaknesses of the other, and vice-versa. Both approaches do, in fact, provide data abstraction; objects by encapsulating the state of the data instance behind procedural abstractions, ADTs by encapsulating that state behind a type boundary. Both also describe (if you squint a bit) common data abstraction patterns. On the other hand, each approach has some peculiarities: because an object only has access to &lt;i&gt;its own&lt;/i&gt; state, &lt;i&gt;complex&lt;/i&gt; operations require weakening the encapsulation of objects. Cook calls "an operation 'complex' if it inspects multiple representations," like for example equality testing; I may not want to expose all of the implementation information necessary to compare two instances in the methods that an object responds to, yet I have no other option in order to implement some observations. Cook claims that object oriented, procedural abstractions are possible in dynamically typed languages but ADTs are not; "abstract data types depend upon a static type system to enforce type abstraction. It is not an accident that dynamic languages use objects instead of user-defined abstract data types. Dynamic languages typically support built-in abstract data types for primitive types; the type abstraction here is enforced by the runtime system."&lt;/p&gt;&lt;p&gt;I do not doubt the validity of this deconstruction of objects and abstract data types, if for no other reason than that it exactly covers Philip Wadler's "expression problem". Also, both ideas seem pretty productive, which is always the primary test of science on the hoof. If that was all there was to it, there would be no mad science involved.&lt;/p&gt;&lt;h2&gt;The mad science part&lt;/h2&gt;&lt;p&gt;&lt;b&gt;Mad Science Tip #1:&lt;/b&gt; If you have to repeat the same message over 20 years, and no one seems to be listening to you, &lt;i&gt;they're&lt;/i&gt; the crazy ones. They're the ones who don't &lt;i&gt;see.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Mad Science Tip #2:&lt;/b&gt; A beautiful theory, one that explains &lt;i&gt;everything&lt;/i&gt;, is obviously true. Even if reality doesn't seem to particularly agree. The ADT half of Cook's papers seems to be relatively uncontroversial, perhaps because no one actually uses the languages (like ML and Haskell) that have user-defined ADTs as the primary data abstraction scheme. On the other hand, Cook's minor point about the inability to use ADTs in dynamically typed languages doesn't seem particularly, well, true; most Lisps, for example, allow you to define structures (or write macros to build such structures) that have representations hidden from any functions other than a limited group. Such pseudo-ADTs may not be as encapsulated as Cook would like, but coupled with a common coding style rule, say "Don't do stupid things," they work well enough. Objects, likewise, do not actually seem to exist. It's been too long since I last used Smalltalk, but every other "object-oriented" language allows a method in a class to access the internals of more than one object of the same class, neatly avoiding (some cases of) the "complex" operation issue. (To avoid all of the difficulties presented by complex operations requires something like multimethods or other techniques that are even more rare.) Maybe some of the object systems for Scheme satisfy the requirements for objects, but &lt;i&gt;Scheme doesn't have a standard &lt;b&gt;anything&lt;/b&gt;, much less an object system; it is a toolkit for implementing other languages.&lt;/i&gt; Further, Cook's ideas on actually doing object-oriented programming in Java would likely horrify most Java-istas, even those that love interfaces as much as I do.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Mad Science Tip #3:&lt;/b&gt; You get extra points for hosting dinner parties where you torment your rivals.&lt;blockquote&gt;What is the relationship between objects and abstract data types (ADTs)? I have asked this question to many groups of computer scientists over the last 20 years. I usually ask it atdinner, or over drinks. The typical response is a variant of “objects are a kind of abstract data type”.&lt;/blockquote&gt; Whereupon he goes all maniacal on them.&lt;/p&gt;&lt;p&gt;Last and possibly least, &lt;b&gt;Mad Science Tip #4:&lt;/b&gt; Being a mad scientist is fun; you get to meet interesting people, there's nothing like the je ne sais quoi of carving your name in the moon with a giant laser. (For that matter, giant lasers are just plain cool no matter what you do with them.) But it may have detrimental effects on your social life.&lt;blockquote&gt;Most groups eventually work through the differences between objects and ADTs, but I can tell they walk away feeling uneasy, as if some familiar signposts now point in different directions.&lt;/blockquote&gt; ...or perhaps as if they're just glad to get away with all the right number of appendages.&lt;/p&gt;&lt;p&gt;Now, I'm not saying William Cook is going to destroy the world if Java 8 doesn't get objects &lt;i&gt;right&lt;/i&gt;. But if you see him being followed by a giant tongue monster or psychopathic, hyper-intelligent gerbils, don't say I didn't warn you.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5510162608062931828?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/5510162608062931828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5510162608062931828' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5510162608062931828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5510162608062931828'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/12/mad-science-abstract-data-types-and.html' title='Mad science, abstract data types, and objects'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-821177125983421055</id><published>2011-12-08T16:22:00.001-06:00</published><updated>2011-12-11T16:15:54.087-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='random'/><title type='text'>8,827,520 pixels!</title><content type='html'>&lt;ul&gt;&lt;li&gt;1440 x 900 on the (old) laptop,&lt;/li&gt;&lt;li&gt;3840 x 1080 in two monitors on the (new) laptop,&lt;/li&gt;&lt;li&gt;1920 x 1080 and 1280 x 1024 on the Mac.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We had a short-lived competition. I won only briefly.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-821177125983421055?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/821177125983421055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=821177125983421055' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/821177125983421055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/821177125983421055'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/12/8827520-pixels.html' title='8,827,520 pixels!'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-3676791671874032721</id><published>2011-12-08T12:17:00.000-06:00</published><updated>2011-12-10T21:29:27.642-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><title type='text'>Quote o' the day: flagrant reticulation</title><content type='html'>&lt;p&gt;In a reply to Ben Collins-Sussman's post, &lt;a href="http://blog.red-bean.com/sussman/?p=597"&gt;Your Community is NOT Your Tools&lt;/a&gt;, MarkusQ writes:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I think some of the git-resistance comes from different cultural assumptions around the cost of merging. I know from an svn mindset, the “mash the branches together and call it merged” mindset of the git-world can seem a little fast and loose. Likewise, I suspect the older “merging is to be approached with fear and reverence” culture may seem hidebound when you’re used to the &lt;b&gt;flagrant reticulation&lt;/b&gt;, devil take the hindmost style that the git world embraces.&lt;/p&gt;&lt;p&gt;– MarkusQ&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;For those of you too lazy to look it up yourself,&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;$ dict reticulation&lt;br /&gt;2 definitions found&lt;br /&gt;&lt;br /&gt;From The Collaborative International Dictionary of English v.0.48 [gcide]:&lt;br /&gt;&lt;br /&gt;  Reticulation \Re*tic`u*la"tion\, n.&lt;br /&gt;     The quality or state of being reticulated, or netlike; that&lt;br /&gt;     which is reticulated; network; an organization resembling a&lt;br /&gt;     net.&lt;br /&gt;     [1913 Webster]&lt;br /&gt;  &lt;br /&gt;           The particular net you occupy in the great&lt;br /&gt;           reticulation.                            --Carlyle.&lt;br /&gt;     [1913 Webster]&lt;br /&gt;&lt;br /&gt;From WordNet (r) 3.0 (2006) [wn]:&lt;br /&gt;&lt;br /&gt;  reticulation&lt;br /&gt;      n 1: (photography) the formation of a network of cracks or&lt;br /&gt;           wrinkles in a photographic emulsion&lt;br /&gt;      2: an arrangement resembling a net or network; "the reticulation&lt;br /&gt;         of a leaf"; "the reticulation of a photographic emulsion"&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The only way to get more points would have been to work in "squamous".&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3676791671874032721?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/3676791671874032721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3676791671874032721' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3676791671874032721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3676791671874032721'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/12/quote-o-day-flagrant-reticulation.html' title='Quote o&apos; the day: flagrant reticulation'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-5113225659446032298</id><published>2011-12-02T23:38:00.000-06:00</published><updated>2011-12-02T23:38:02.329-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='link'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><title type='text'>Link o' the week: Bayes' Theorem</title><content type='html'>&lt;p&gt;I seem to be up to my armpits in Bayesian statistics. Between &lt;a href="https://www.ai-class.com/home/"&gt;Thrun and Norvig's AI class&lt;/a&gt; (the AI classes I took back in the late '80's and early '90's primarily dealt with state-space search, neural networks, and predicate logic; there was nary a statistic to be found) and the very good textbook I ran across, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0123814855/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0123814855"&gt;Doing Bayesian Data Analysis: A Tutorial with R and BUGS&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0123814855" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt; by &lt;a href="http://www.indiana.edu/~kruschke/DoingBayesianDataAnalysis/"&gt;John K. Kruschke&lt;/a&gt;, this stuff seems to be appearing everywhere.&lt;/p&gt;&lt;p&gt;Then I ran across Eliezer Yudkowsky's post, &lt;a href="http://yudkowsky.net/rational/bayes"&gt;An Intuitive Explanation of Bayes' Theorem&lt;/a&gt;. Now, intuition is a funny thing. It is not innate as most people seem to think, you have to train it. Yudkowsky does that, going over the same ground with many examples and good explanations. Better, his writing, like Kruschke's, is light and entertaining:&lt;blockquote&gt;&lt;table style="border:medium solid black;background-color: #CFF;"&gt;&lt;tr&gt;&lt;td rowspan="11" style="vertical-align:text-top; border:thin solid black;background-color: #FF9;padding:3px;"&gt;&lt;b&gt;Fun Fact!&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;tr style="border-left:thin solid black"&gt;&lt;td&gt;&lt;b&gt;Q.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;How can I find the priors for a problem?&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;A.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;Many commonly used priors are listed in the Handbook of Chemistry and Physics.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Q.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;Where do priors originally come from?&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;A.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;Never ask that question.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Q.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;Uh huh.  Then where do scientists get their priors?&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;A.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;Priors for scientific problems are established by annual vote of the AAAS.  In recent years the vote has become fractious and controversial, with widespread acrimony, factional polarization, and several outright assassinations.  This may be a front for infighting within the Bayes Council, or it may be that the disputants have too much spare time.  No one is really sure.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Q.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;I see.  And where does everyone else get their priors?&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;A.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;They download their priors from Kazaa.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Q.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;What if the priors I want aren't available on Kazaa?&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;A.&lt;/b&gt;&lt;/td&gt;&lt;td&gt;There's a small, cluttered antique shop in a back alley of San Francisco's Chinatown.  Don't ask about the bronze rat.&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/blockquote&gt;&lt;p&gt;Bronze rat aside, I also like the Javascript calculators embedded in the article, allowing a reader to try to figure out the answers to Yudkowsky's examples without dredging up another app.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5113225659446032298?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/5113225659446032298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5113225659446032298' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5113225659446032298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5113225659446032298'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/12/link-o-week-bayes-theorem.html' title='Link o&apos; the week: Bayes&apos; Theorem'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-4287010422610417773</id><published>2011-11-30T10:58:00.001-06:00</published><updated>2011-11-30T11:10:19.521-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Quote o' the day: Coda Hale on the value of communities</title><content type='html'>&lt;p&gt;&lt;a href="http://codahale.com/"&gt;Coda Hale&lt;/a&gt; wrote a widely publicized &lt;a href="http://codahale.com/the-rest-of-the-story/"&gt;private&lt;/a&gt; &lt;a href="https://gist.github.com/1406238?1"&gt;email&lt;/a&gt; to the-powers-that-be-in-Scala with the following line:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;...but at some point a best practice emerged: ignore the community entirely.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Actually, there are some lessons there: Language communities are nice and fun and wonderful, but they may not be good ways of learning "best practices", whatever those are. It sucks to be an early adopter. (On the other hand, not having &lt;i&gt;any&lt;/i&gt; early adopters isn't good either.) Oh, and if anyone asks you if they look fat, don't answer them.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-4287010422610417773?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/4287010422610417773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=4287010422610417773' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4287010422610417773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4287010422610417773'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/11/quote-o-day-coda-hale-on-value-of.html' title='Quote o&apos; the day: Coda Hale on the value of communities'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-2381928848000927430</id><published>2011-11-24T11:27:00.000-06:00</published><updated>2011-11-25T16:40:32.430-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='link'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Consolidated Reference List for the Software Engineering Body of Knowledge, Pt. 2</title><content type='html'>&lt;p&gt;This post contains the second half of a somewhat annotated version of the Consolidated Reference List for the IEEE Software Engineering Body of Knowledge (SWEBOK). You may want to start with the &lt;a href="http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for-ieee.html"&gt;previous half&lt;/a&gt;.&lt;/p&gt;&lt;ol start="19"&gt;&lt;li&gt;&lt;p&gt;A. Lopez-Ortiz. (1998, July 22, 2010). &lt;i&gt;&lt;a href="http://www.cs.uwaterloo.ca/~alopez-o/math-faq/mathtext/node6.html"&gt;Algebraic Structures&lt;/a&gt;&lt;/i&gt;. Available: &lt;a href="http://www.cs.uwaterloo.ca/~alopez-o/math-faq/mathtext/node6.html"&gt;http://www.cs.uwaterloo.ca/~alopez-o/math-faq/mathtext/node6.html&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;This one is more than a tiny bit ridiculous. The link is to the &lt;a href="http://www.cs.uwaterloo.ca/~alopez-o/math-faq/mathtext/math-faq.html"&gt;Frequently Asked Questions in Mathematics&lt;/a&gt; list from the Sci.Math FAQ Team. The specific link is to the section on algebraic structures: monoids, groups, rings, fields, and ordering. I'm sure that even the Sci.Math FAQ Team would find the reference to their FAQ in this list silly, if not insulting. Is that &lt;em&gt;really&lt;/em&gt; all you need to know about abstract mathematics? Why not link to the FAQ's &lt;a href="http://www.cs.uwaterloo.ca/~alopez-o/math-faq/mathtext/node43.html#SECTION0012000000000000000000"&gt;bibliography&lt;/a&gt;, one of the texts in it, or even my favorite, &lt;a href="http://www.amazon.com/gp/product/0486474178/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0486474178"&gt;A Book of Abstract Algebra&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0486474178&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;?&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;S. McConnell, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0735619670/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0735619670"&gt;Code Complete: A Practical Handbook of Software Construction&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0735619670&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 2nd ed. Redmond, WA: Microsoft Press, 2004.&lt;/p&gt;&lt;p&gt;Unlike the previous, this text is completely unsurprising. McConnell's is one of the most popular books on programming and is likely filled with information that a professional software developer cannot live without. I personally don't know; I don't have a copy. You see, when I was first looking at it in a bookstore many years ago, I flipped to the section on recursion to see what he had to say:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;One problem with computer-science textbooks is that they present silly examples of recursion. The typical examples are computing a factorial or computing a Fibonacci sequence. Recursion is a powerful tool, and it's really dumb to use it in either of those cases. &lt;b&gt;If a programmer who worked for me used recursion to compute a factorial, I'd hire someone else.&lt;/b&gt; Here's the recursive version of the factorial routine:&lt;/p&gt;&lt;pre&gt;&lt;br /&gt; int Factorial( int number ) {&lt;br /&gt;    if ( number == 1 ) {&lt;br /&gt;      return 1;&lt;br /&gt;    } else {&lt;br /&gt;      return number * Factorial( number - 1 );&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;In addition to being slow and making the use of run-time memory unpredictable, &lt;b&gt;the recursive version of this routine is harder to understand than the iterative version&lt;/b&gt;, which follows:&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;  int Factorial( int number ) {&lt;br /&gt;    int intermediateResult = 1;&lt;br /&gt;    for ( int factor = 2; factor &lt;= number; factor++ ) {&lt;br /&gt;      intermediateResult = intermediateResult * factor;&lt;br /&gt;    }&lt;br /&gt;    return intermediateResult;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;(Emphasis mine.) Now, where to start with this passage? Recursion &lt;i&gt;is&lt;/i&gt; a powerful tool, and in some programming languages that McConnell may not be familiar with, it's &lt;em&gt;fundamental&lt;/em&gt;; there may not even be any other iteration structures. So, whether it's dumb to use it in any specific case is a more difficult question than he seems to think. Heck, even most decent modern C compilers include tail call optimization, so the speed and memory use of recursion is an open question. On the other hand, McConnell previously presented as a &lt;em&gt;good&lt;/em&gt; use of recursion a maze-solving function; maze solving is an application of state-space search, which has a simple, clear, and wildly flexible implementation based on a priority queue. Further, I find it simply bizarre that McConnell believes a recursive version of factorial is "harder to understand" than the iterative version. Quick! Prove to me that his two versions actually compute a factorial:&lt;/p&gt;\[n! = \begin{array}{lr}1 &amp;amp; \textrm{if \(n\) = 1} \\n * (n-1)! &amp;amp; \textrm{if \(n\) &gt; 1}\end{array}\]&lt;p&gt;Finally, there's the whole "If a programmer who worked for me...I'd hire someone else" thing. The sections before and after recursion are on multiple returns in a routine and goto's; I'm afraid to look at either.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;S. J. Mellor and M. J. Balcer, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0201748045/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0201748045"&gt;Executable UML: A Foundation for Model-Driven Architecture&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0201748045&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 1st ed. Boston: Addison-Wesley, 2002.&lt;/p&gt;&lt;p&gt;This is another topic that leaves me cold. UML is good enough for what it is, a way of communicating ideas about a project, and I'm certainly a programming language collector. However, I have never felt that UML would make a good programming language, which is exactly what xUML and other executable model languages are.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;D. C. Montgomery and G. C. Runger, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0470053046/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0470053046"&gt;Applied Statistics and Probability for Engineers&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0470053046&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 4th ed. Hoboken, NJ: Wiley, 2007.&lt;/p&gt;&lt;p&gt;(The link is to the fifth edition.) Statistics and I have an uneasy relationship. I know there is a great deal of value in statistical data analysis, as an end itself as well as about the software development process. On the other hand, I don't really know much about the topic, and I reference my previous comments about lacking numerical methods experience and thus my inability to use floating point numbers. Anyway, it's an important topic; this may or may not be a good reference (several of the Amazon reviewers mention errors in the text), and I don't have a better one at hand. Your mileage may vary.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;J. W. Moore, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0471683620/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0471683620"&gt;The Road Map to Software Engineering: A Standards-Based Guide&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0471683620&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 1st ed. Hoboken, NJ: Wiley-IEEE Computer Society Press, 2006.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The Road Map to Software Engineering organizes relevant IEEE software and systems standards, along with standards from other sources, using two frameworks: the SWEBOK Guide's topical knowledge areas and the widely used &lt;a href="http://standards.ieee.org/findstds/standard/12207.0-1996.html"&gt;IEEE/EIA 12207 standard&lt;/a&gt; [IEEE Standard for Information Technology - Software Life Cycle Processes].&lt;/p&gt;&lt;p&gt;&lt;i&gt;The Road Map to Software Engineering&lt;/i&gt; allows practitioners to quickly locate the standards pertinent to questions arising in real projects. Providing students with a comprehensive body of knowledge, the text also assists experienced professionals in finding and filling gaps in their understanding.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Probably a vital reference for those using official standards; probably not something I need.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;J. Nielsen, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0125184069/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0125184069"&gt;Usability Engineering&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0125184069&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 1st ed. Boston: Morgan Kaufmann, 1993.&lt;/p&gt;&lt;p&gt;Jakob Nielsen is a very good writer on usability topics. I own and appreciate a copy of his &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/156205810X/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=156205810X"&gt;Designing Web Usability&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=156205810X&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt; even though my idea of usability seems to differ strongly from others'. I will be getting a copy, since I was not previously aware if this. On the other hand, this is nearly 20 years old; is there no more recent reference?&lt;/p&gt;&lt;p&gt;Update: I just got a copy of this book, and I am very impressed so far. The emphasis, at least from the parts I have read so far, is on providing basic usability information and usability testing techniques that &lt;em&gt;do not&lt;/em&gt; require massive investments of resources. I do not have the book handy while I'm writing this, but if I interpret Nielsen correctly he writes that a (quantifiable) big win can be had by simply observing actual users for a few hours, and by asking them what they think.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;L. Null and J. Lobur, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/1449600069/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=1449600069"&gt;Essentials of Computer Organization and Architecture&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=1449600069&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 2nd ed. Sudbury, MA: Jones and Bartlett Publishers, 2006.&lt;/p&gt;&lt;p&gt;(Link is to the third edition.) I love Linda Null's name, let me get that out of the way. Computer architecture is a topic I know a bit about, and, although I'm not familiar with this book, it does seem to cover most of the bases appropriately. Certainly, if a programmer who worked for me &lt;i&gt;didn't&lt;/i&gt; know a good bit of this stuff, I'd hire someone else. But this text seems to relegate parallel and concurrent architectures to a section of a chapter on alternative organizations, which is somewhat surprising given the not-so-recent trend towards those architectures. There doesn't even seem to be anything on pipelines, which is vital for high-performance software. Another book, &lt;a href="http://www.amazon.com/gp/product/0136073735/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0136073735"&gt;&lt;i&gt;Computer Organization and Architecture: Designing for Performance&lt;/i&gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0136073735&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt; by William Stallings, does have extensive coverage of parallel architectures although it looks to be less clear and well organized. Given the choice, I would probably favor clarity over coverage.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;M. Page-Jones, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/020169946X/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=020169946X"&gt;Fundamentals of Object-Oriented Design in UML&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=020169946X&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 1st ed. Reading, MA: Addison-Wesley, 1999.&lt;/p&gt;&lt;p&gt;Object-oriented design and programming are not the end-all of software development strategies. It is not appropriate for everything, and an uncritical use of it is not appropriate for &lt;i&gt;anything&lt;/i&gt;. I view it as a technique for &lt;i&gt;managing&lt;/i&gt; complexity since is pretty successful at that while bringing along its own complications. I, on the other hand, would prefer to &lt;i&gt;remove&lt;/i&gt; complexity. That being said, you will need to know &lt;i&gt;a lot&lt;/i&gt; about object-oriented design, and Page-Jones is probably a good-enough teacher. (I have his &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0136907695/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0136907695"&gt;Practical Guide to Structured Systems Design&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0136907695&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt; and don't know of anything wrong with it.) On the other hand, if you need a guide to UML, I prefer &lt;em&gt;&lt;a href="http://www.amazon.com/gp/product/0321193687/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0321193687"&gt;UML Distilled: A Brief Guide to the Standard Object Modeling Language&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0321193687&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/em&gt; by Martin Fowler.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;G. K. Palshikar, "&lt;a href="http://csdl.computer.org/comp/mags/so/2001/06/s6089.pdf"&gt;Applying Formal Specifications to Real-World Software Development&lt;/a&gt;," IEEE Software, vol. 18, pp. 89-97, 2001.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;While formal methods are gaining acceptance in the software industry, there is a need for practical guidelines for making the best use of formal specifications. The author provides a few such pragmatic tips for people involved in the industrial use of formal specifications. The 15 guidelines are split into two areas, dealing with process and content. The author also includes a full-page reference for literature available over the Web.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;A very good introduction to the use of formal specification methods. I hope the computer.org link above is available to non-IEEE and non-Computer Society members; if it isn't, please let me know. I am tempted to throw propriety (and copyright) out the window and host a link to this paper myself.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;S. Redwine, "&lt;a href="http://www2.computer.org/cms/Computer.org/SWEBOK/Information-for-Item-Writers-v14.pdf"&gt;Security-Oriented Pointwise Changes to SWEBOK Guide&lt;/a&gt;," 2009. Available: &lt;a href="http://www2.computer.org/cms/Computer.org/SWEBOK/Information-for-Item-Writers-v14.pdf"&gt;http://www2.computer.org/cms/Computer.org/SWEBOK/Information-for-Item-Writers-v14.pdf&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The original set of suggested changes to the 2004 SWEBOK to incorporate topics from the new security knowledge area. This paper is probably only useful in conjunction with that version of the SWEBOK guide. As an addition, two of the three referenced texts are &lt;i&gt;Software Security Engineering&lt;/i&gt; and &lt;i&gt;Computer Security&lt;/i&gt;, already found on this consolidated reference list; the third is Summerville's &lt;i&gt;Software Engineering&lt;/i&gt; below. A fourth reference is to "&lt;a href="https://buildsecurityin.us-cert.gov/bsi/940-BSI/version/default/part/AttachmentData/data/CurriculumGuideToTheCBK.pdf"&gt;Software Assurance: A Curriculum Guide to the Common Body of Knowledge to Produce, Acquire, and Sustain Secure Software Version 1.2&lt;/a&gt;", edited by Redwine and from the US Department of Homeland Security. (My tax dollars at work!)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;K. Rosen, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0073383090/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0073383090"&gt;Discrete Mathematics and Its Applications&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0073383090&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 6th ed. Boston: McGraw-Hill, 2006.&lt;/p&gt;&lt;p&gt;(Link is to the seventh edition.) Discrete mathematics is probably more important to software developers than, say, differential and integral calculus, and I'm not just saying that because calculus and I didn't really agree back in my undergraduate years. More information is available from the &lt;a href="http://highered.mcgraw-hill.com/sites/0073383090/information_center_view0/"&gt;McGraw-Hill site for the book&lt;/a&gt;, including a sample chapter.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;A. Silberschatz, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0470128720/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0470128720"&gt;Operating System Concepts&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0470128720&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 8th ed. Hoboken, NJ: Wiley, 2008.&lt;/p&gt;&lt;p&gt;True story: I was at a conference looking at the forthcoming books table and a full professor near me pointed to a copy of a new edition of one of Avi's (Abraham Silberschatz) books and asked "Avi has another kid going to college?" I seem to recall learning operating systems from a previous edition of this text, and databases from another of Avi's books, and I haven't been adversely affected. (The tics have mostly gone away.) They are pretty common, for a good reason, but there are alternatives from &lt;a href="http://www.amazon.com/gp/product/0136006639/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0136006639"&gt;Tanebaum&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0136006639&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;, &lt;a href="http://www.amazon.com/gp/product/0136006329/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0136006329"&gt;Stallings&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0136006329&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;, &lt;a href="http://www.amazon.com/gp/product/0131828274/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0131828274"&gt;Deitel&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0131828274&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;, and probably others that are just as good.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;I. Sommerville, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0137035152/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0137035152"&gt;Software Engineering&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0137035152&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 8th ed. New York: Addison-Wesley, 2006.&lt;/p&gt;&lt;p&gt;(Link is to the ninth edition.) A general text on software engineering, this got good reviews from Dr. Tom Hilburn, who taught the software engineering course at the IEEE Smart Tech mini-conference. It's about 800 pages and should be good to bludgeon many, many infidel software developers, managers, and what-not.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The Data and Analysis Center for Software. (2008, July 22, 2010). &lt;a href="https://goldpractice.thedacs.com/practices/gqm/"&gt;Goal-Question-Metric (GQM) Approach&lt;/a&gt;. Available: &lt;a href="https://goldpractice.thedacs.com/practices/gqm/"&gt;https://www.goldpractices.com/practices/gqm/&lt;/a&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;GQM is a top-down approach to establish a goal-driven measurement system for software development, in that the team starts with organizational goals, defines measurement goals, poses questions to address the goals, and identifies metrics that provide answers to the questions.... [It] is particularly useful for the following purposes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Understanding and baselining an organization’s software practices&lt;/li&gt;&lt;li&gt;Guiding and monitoring software processes&lt;/li&gt;&lt;li&gt;Assessing new software engineering technologies&lt;/li&gt;&lt;li&gt;Evaluating and certifying improvement activities&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;GQM seems to be a general, relatively process-agnostic method for generating metrics for software development processes; it looks interesting. I need to look at it further.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;S. Tockey, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0321228758/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0321228758"&gt;Return on Software: Maximizing the Return on Your Software Investment&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0321228758&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 1st ed. Boston: Addison-Wesley, 2004.&lt;/p&gt;&lt;p&gt;Assuming this book does what it claims, it would be a very good text to have around. Particularly given the recent appearances of "&lt;a href="http://www.kalzumeus.com/2011/10/28/dont-call-yourself-a-programmer/"&gt;Don't call yourself a programmer&lt;/a&gt;" postings, giving career advice on the advantages of appealing to the business side of technical decisions.&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;Estimate how much each proposed software technical decision will cost, and how much it will return.&lt;/li&gt;&lt;li&gt;Weigh the time frames for a software decision's costs and benefits against each other to reveal when there might be a more important factor than schedule.&lt;/li&gt;&lt;li&gt;Attach a value to quality and produce a rational answer to the question, "How much testing is enough?"&lt;/li&gt;&lt;li&gt;Account for risk and uncertainty in software technical decisions, such as when considering a new technology.&lt;/li&gt;&lt;li&gt;Communicate your decisions in a way that speaks to the all-important bottom line.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;Also from the back cover:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;"This just what the doctor ordered to help software programs solve the problem of how to introduce engineering economics and business decision-making into their curricula. The economics of software development should not only be part of any computing curriculum they are an essential element of recent accreditation and certification recommendations.&lt;/p&gt;&lt;p&gt;This book is an accessible and relevant text for any student of software engineering. The style is clear and straightforward and the software examples will be appealing to students and faculty alike. I can't wait to use it in class!"&lt;/p&gt;&lt;p&gt;Thomas B. Hilburn, Professor&lt;br /&gt;Department of Computer and Software Engineering&lt;br /&gt;Embry-Riddle Aeronautical University&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The &lt;a href="http://www.informit.com/articles/article.aspx?p=332848"&gt;introduction&lt;/a&gt; of the book is available online; I especially like this paragraph:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;In another case I was developing software to monitor radiation at nuclear power plants. Part of that software needed a sorting routine. I wrote a simple insertion sort routine and had that part of the system running in a matter of hours. A coworker insisted on developing a QuickSort routine because "everybody knows that QuickSort is better than insertion sort." At that time (early 1980s) reusable QuickSort routines weren't available; if you wanted one, you had to write it yourself. Unfortunately, QuickSort is a recursive algorithm, and the programming language we were using, Fortran-IV, didn't support recursion. My coworker spent more than a week developing QuickSort in Fortran-IV. Only later did he realize that the list that needed sorting averaged only about 30 entries and was predominantly sorted to begin with. Small lists that are already mostly sorted cause QuickSort to have extremely poor performance, typically worse than simpler algorithms such as insertion sort. Moreover, sorting happened in this system fewer than 50 times a day. Even if QuickSort did perform better than insertion sort, it would take decades for the company to recover its investment. My coworker's effort turned out to be a pretty big waste of the company's money and time.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This is going onto my shopping cart.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;G. Voland, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0131409190/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0131409190"&gt;Engineering by Design&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0131409190&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 2nd ed. Upper Saddle River, NJ: Prentice Hall, 2003.&lt;/p&gt;&lt;p&gt;This looks to be a very interesting book, and I'm saying that as a Henry Pretrovski addict. Judging by what I can find, it appears to come from the physical object design world.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The book introduces readers to a broad range of important design topics. It provides numerous cases that illustrate both successes and failures in engineering design; qualitative presentation of engineering practices are easily understood by readers with little technical knowledge, and analytical techniques are given that allow the development and evaluation of proposed engineering solutions. Coverage includes: an overview of engineering design, needs assessment, structuring the search for the problem, structuring the search for a solution (design goals and specifications), acquiring and applying technical knowledge, abstraction and modeling, synthesis, ethics and product liability issues, and hazards analysis and failure analysis. An excellent handbook for design engineers.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Gerard Voland is Provost and Vice Chancellor at the University of Michigan-Flint. I've got no idea if that is a good thing or a bad thing.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;K. E. Wiegers, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0735618798/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0735618798"&gt;Software Requirements&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0735618798&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, 2nd ed. Redmond, WA: Microsoft Press, 2003.&lt;/p&gt;&lt;p&gt;A book about requirements engineering. Keep in mind that, whatever I say about this book, the only reliable way I have found to identify, analyze, and satisfy requirements is by some variant of the "agile", open-source, throw-it-at-the-wall-and-see-what-sticks approach (which cannot with any justice be called prototyping). I do have a copy of the follow-on, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0735622671/ref=as_li_ss_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0735622671"&gt;More About Software Requirements: Thorny Issues and Practical Advice&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0735622671&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, and have not seen anything particularly wrong in it. Just not very applicable.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;J. M. Wing, "&lt;a href="http://www.cs.cmu.edu/~wing/publications/Wing90a.pdf"&gt;A Specifier's Introduction to Formal Methods&lt;/a&gt;," Computer, vol. 23, pp. 8, 10-23, 1990.&lt;/p&gt;&lt;p&gt;I found two links to PDF versions of this paper, one a copy of &lt;a href="http://www.cs.cmu.edu/~wing/publications/Wing90a.pdf"&gt;the article as it appeared&lt;/a&gt; in &lt;em&gt;Computer&lt;/em&gt; and the other a CMU technical report, &lt;a href="http://www.cs.cmu.edu/~wing/publications/CMU-CS-90-136.pdf"&gt;CMU-CS-90-136&lt;/a&gt;. Pick the way you want to read it, I guess.&lt;/p&gt;&lt;p&gt;This paper is a decent introduction to formal methods, including examples of a fair number of specific techniques in the last half, as they stood in 1990. There is nothing really wrong with that; there have only been a few major changes in formal methods since then. Z (pronounced "Zed") and communicating sequential processes both appear, and both are as relevant or irrelevant as they ever were. (As an aside, I have a small stack of very good Z books.) I did not see anything covering model checking, and there certainly was nothing on dependently typed programming languages, two of what I believe to be the biggest changes in formal methods. That aside, it is a pretty good read.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-2381928848000927430?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/2381928848000927430/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=2381928848000927430' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2381928848000927430'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2381928848000927430'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for.html' title='Consolidated Reference List for the Software Engineering Body of Knowledge, Pt. 2'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-2951372889504955161</id><published>2011-11-21T23:02:00.000-06:00</published><updated>2011-11-25T16:42:08.459-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='link'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Consolidated Reference List for the IEEE Software Engineering Body of Knowledge</title><content type='html'>This is the first half of a none-too-serious annotated bibliography of the &lt;a href="http://www.computer.org/portal/web/swebok/consolidated_reference_list"&gt;references&lt;/a&gt; that the IEEE Computer Society has identified as the most important sources for its Software Engineering Body of Knowledge (SWEBOK). (When you get done with this, you can read the &lt;a href="http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for.html"&gt;second part&lt;/a&gt;.) Note: I have not actually read &lt;i&gt;all&lt;/i&gt; (or most, for that matter) of these books, nor do I intend to. I will identify those I have, and those I have not are evaluated on what I, as a professional, think of their publicly available information. You have been warned.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;A. Abran, et al., Eds., &lt;i&gt;&lt;a href="http://www.computer.org/portal/web/swebok/html/contents"&gt;Guide to the Software Engineering Body of Knowledge&lt;/a&gt;&lt;/i&gt;. Los Alamitos, CA: IEEE Computer Society, 2004.&lt;br /&gt;This consolidated reference list (if I were a true software engineer, I would have written that as "CRL") is associated with the version 3 of the SWEBOK (which is really too long to type out). However, because that version is still in development, it refers to the previous, 2004 version. The new version is supposed to add knowledge areas on professionalism, software engineering economics, mathematical and computing foundations, and possibly measurement and security, and revise the existing structure. Duck and cover!&lt;br /&gt;&lt;/li&gt;&lt;li&gt;J. H. Allen, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/032150917X/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=032150917X"&gt;Software Security Engineering: A Guide for Project Managers&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=032150917X&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;. Upper Saddle River, NJ: Addison-Wesley, 2008.&lt;br /&gt;Yes. Well. So, any book with "managers" in the title leaves me with a sort of squishy feeling, particularly as a reference for practitioners. The advertising text doesn't really help:&lt;br /&gt;&lt;blockquote&gt;One view of secure software is software that is engineered “so that it continues to function correctly under malicious attack” [McGraw 2006] and is able to recognize, resist, tolerate, and recover from events that intentionally threaten its dependability. Broader views that can overlap with software security (for example, software safety, reliability, and fault tolerance) include the notion of proper functioning in the face of unintentional failures or accidents and inadvertent misuse and abuse, as well as reducing software defects and weaknesses to the greatest extent possible regardless of their cause. This book addresses the &lt;b&gt;narrower view&lt;/b&gt;.&lt;/blockquote&gt;(Emphasis mine.) Personally, I do not really feel I need to "increase [my] awareness and understanding of the security issues in the design and development of software"; rather I need good information on producing secure systems or, better yet, a general approach that leads to secure systems by construction. But then, I suspect I take the broader view described above.&lt;/li&gt;&lt;li&gt;M. Bishop, &lt;a href="http://www.amazon.com/gp/product/0201440997/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0201440997"&gt;&lt;i&gt;Computer Security: Art and Science&lt;/i&gt;&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201440997&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;. Boston: Addison-Wesley, 2002.&lt;br /&gt;This sounds like a much more useful book. It seems to have gotten good reviews in both &lt;i&gt;SysAdmin&lt;/i&gt; and by Peter Salus in &lt;i&gt;;login&lt;/i&gt;, and appears to be an attempt at a complete reference tome. There are a couple of &lt;a href="http://nob.cs.ucdavis.edu/book/book-aands/index.html"&gt;chapters available online&lt;/a&gt; at Bishop's UC Davis page; &lt;a href="http://nob.cs.ucdavis.edu/book/book-aands/aands13.pdf"&gt;Chapter 13: Design Principles&lt;/a&gt; leaves me interested.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Principle of Least Privilege&lt;/li&gt;&lt;li&gt;Principle of Fail-Safe Defaults&lt;/li&gt;&lt;li&gt;...Economy of Mechanism&lt;/li&gt;&lt;li&gt;...Complete Mediation&lt;/li&gt;&lt;li&gt;...Open Design&lt;/li&gt;&lt;li&gt;...Separation of Privilege&lt;/li&gt;&lt;li&gt;...Least Common Mechanism&lt;/li&gt;&lt;li&gt;...Psychological Acceptability&lt;/li&gt;&lt;/ul&gt;Bishop also has an alternate version, &lt;a href="http://www.amazon.com/gp/product/0321247442/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0321247442"&gt;&lt;i&gt;Introduction to Computer Security&lt;/i&gt;&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321247442&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;, that "omits much of the mathematical formalism, making it more accessible for professionals and students who have a less formal mathematical background, or for readers with a more practical than theoretical interest". I think I may have to get a copy of &lt;i&gt;Computer Security: Art and Science&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;B. Boehm and R. Turner, &lt;a href="http://www.amazon.com/gp/product/0321186125/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0321186125"&gt;&lt;i&gt;Balancing Agility and Discipline: A Guide for the Perplexed&lt;/i&gt;&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321186125&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;. Boston: Addison-Wesley, 2003.&lt;br /&gt;This book about agile software development processes also looks pretty interesting. One common complaint about agile methods from traditional or more engineering-oriented developers is that they are undisciplined; a common complaint from agile developers is that more disciplined processes are unusable. Both are ironic, since most methods are followed in name only, in my experience.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;F. Bott, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0748409513/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0748409513"&gt;Professional Issues in Software Engineering&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0748409513&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;, 3rd ed. New York: Taylor &amp;amp; Francis, 2000.&lt;br /&gt;&lt;i&gt;Professional Issues in Software Engineering&lt;/i&gt; looks like a good reference to, well, professional issues: the profession and professional organizations, economics, contracts, intellectual property, employee relations, health and safety, liability, criminal law, and regulation of personal information are all represented in the table of contents. Now, professional issues may not interest most developers (or anybody else), but they are something that I am beginning to appreciate more, and something that I detect a serious lack of, now that I have moved into less technically-oriented employment. (Ahem.)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;J. G. Brookshear, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0132569035/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399373&amp;amp;creativeASIN=0132569035"&gt;Computer Science: An Overview&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0132569035&amp;amp;camp=217145&amp;amp;creative=399373" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;, 10th ed. Boston: Addison-Wesley, 2008.&lt;br /&gt;Again, this is an introductory text that doesn't seem to be terribly useful to someone engaged in the profession of creating software systems.&lt;br /&gt;&lt;blockquote&gt;Computer Science: An Overview uses broad coverage and clear exposition to present a complete picture of the dynamic computer science field. Accessible to students from all backgrounds, Glenn Brookshear uses a language-independent context to encourage the development of a practical, realistic understanding of the field. An overview of each of the important areas of Computer Science (e.g. Networking, OS, Computer Architecture, Algorithms) provides students with a general level of proficiency for future courses.&lt;/blockquote&gt;On the other hand, it looks like a very good book to give to someone who wants to know what computer science is &lt;i&gt;about&lt;/i&gt;. On the &lt;i&gt;other&lt;/i&gt;, other hand, however, it seems a little pricey.(The link is to the more-recent 11th edition.)&lt;/li&gt;&lt;li&gt;D. Budgen, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0201722194/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0201722194"&gt;Software Design&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201722194&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;, 2nd ed. New York: Addison-Wesley, 2003.&lt;br /&gt;I have my own ideas about the concept of software design, which I will keep to myself for the moment. In the mean time, this book appears to be more of a meditation on what "design" is than a useful guide to software designs-man-ship. The three parts of the book are the nature of the design process, transferring design knowledge (which includes a chapter on "some design representations" and a chapter on design patterns), and design practices; the last breaks down into chapters on stepwise refinement, incremental design, structured analysis and design, Jackson Structured Programming, Jackson System Development, object-oriented design, component-based design, and the formal approach to design. Certainly, it seems a limited and idiosyncratic choice of topics.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;E. W. Cheney and D. R. Kincaid, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0495114758/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0495114758"&gt;Numerical Mathematics and Computing&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0495114758&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;, 6th ed. Belmont, CA: Brooks/Cole, 2007.&lt;br /&gt;Strangely, I do not know either Ward Cheney or David Kincaid, although I've heard of the latter often enough. Also, I have never taken a course on numerical methods, which by my own rules means that I should never use floating-point numbers. I am afraid all I can say is that this looks like a textbook on numerical methods. Enjoy!&lt;br /&gt;&lt;/li&gt;&lt;li&gt;P. Clements, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0321552687/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0321552687"&gt;Documenting Software Architectures: Views and Beyond&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321552687&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;. Boston: Addison-Wesley, 2002.&lt;br /&gt;This is a text on documenting software architectures. That is probably not as goofy an idea as it sounds, since the architecture of a system is, in the first place, somewhat fundamental to the software, but, in the second, usually hidden behind the mass of trees. The actual architecture of a system may not appear outside of its documentation, and the notation for that documentation may well guide the architecture you get. Note: I'm still reserving my ideas about design and indeed, architecture.&lt;br /&gt;One reviewer on Amazon writes that this book is an extension of the Carnegie Mellon Software Engineering Institute technical report &lt;a href="http://www.sei.cmu.edu/library/abstracts/reports/01tn010.cfmCMU/SEI-2001-TN-010%20-%20Documenting%20Software%20Architectures:%20Organization%20of%20Documentation%20Package"&gt;CMU/SEI-2001-TN-01, &lt;i&gt;Documenting Software Architectures: Organization of Documentation Package&lt;/i&gt;&lt;/a&gt; by a subset of the authors.  That document may be a good place to start. (Book link is to the second edition.)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;L. Copeland, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/158053791X/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=158053791X"&gt;A Practitioner's Guide to Software Test Design&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=158053791X&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;, 1st ed. Boston: Artech House, 2004.&lt;br /&gt;This book seems to be a decent reference to some various forms of test design, black box and white box. On the other hand, the only references to unit testing are in chapter 1, the testing process, under "testing levels", and the introduction to white box testing. Test-driven development is not mentioned at all. In other words, it is a reference to &lt;i&gt;old-school&lt;/i&gt; test methods. Not that those are unnecessary or detrimental, just that they are the kinds of things you run less than frequently, just prior to a release. Knowing how they work will certainly expand your options, even if you are into TDD, and &lt;em&gt;somebody&lt;/em&gt; in your project will probably need to know this stuff.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;R. E. Fairley, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0470294558/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0470294558"&gt;Managing and Leading Software Projects&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0470294558&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;. Hoboken, NJ: Wiley-IEEE Computer Society Press, 2009.&lt;br /&gt;Some management topics are necessary to development projects: estimating, measuring, and risks. I might just buy it for this sentence on the back cover:&lt;br /&gt;&lt;blockquote&gt;It introduces software development methods, from traditional (&lt;b&gt;hacking&lt;/b&gt;, requirements to code, and waterfall) to iterative (incremental build, evolutionary, agile, and spiral), and illustrates and emphasizes how to tailor the development process to specific projects.&lt;/blockquote&gt;(Emphasis mine.) On page 54, "hacking" is characterized by a reference to the cartoon with the caption, "You start coding and I'll go find out what they want," which is actually a pretty fair description of one of the few ways I know to reliably come up with a project's requirements.&lt;/li&gt;&lt;li&gt;[12] E. Gamma, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0201633612/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0201633612"&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201633612&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;, 1st ed. Reading, MA: Addison-Wesley Professional, 1994.&lt;br /&gt;And finally, a book that I own and have read. Now, this is an important book, and contains many good ideas, both for software designs and for communicating those designs. Yet, I am not a pattern-ista. In fact, I am of the set that regards design patterns as work-arounds for poor programming languages. Still, the contents of this book are probably necessary, if you are going to hang around software development for very long.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;T. Gilb and D. Graham, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0201631814/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0201631814"&gt;Software Inspection&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201631814&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;, 1st ed. Reading, MA: Addison-Wesley, 1993.&lt;br /&gt;An inspection is a formal examination of some artifact specifically to detect problems. &lt;br /&gt;&lt;blockquote&gt;Zero-defect software is the Holy Grail of all software developers. It has proved to be an elusive goal - until now. The Inspection techniques illustrated in this book have brought clear benefits in terms of lower (or even zero) defects, higher productivity, better project tracking and improved documentation.&lt;/blockquote&gt;Maybe there is a silver bullet, after all.&lt;/li&gt;&lt;li&gt;P. Grubb and A. A. Takang, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/981238426X/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=981238426X"&gt;Software Maintenance: Concepts and Practice&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=981238426X&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;, 2nd ed. River Edge, NJ: World Scientific Publishing, 2003.&lt;br /&gt;Judging by the table of contents, this looks like an interesting book; it includes how new development differs from maintenance, what takes place during maintenance (program understanding, reverse engineering, reuse, testing), and tools. On the other hand, the authors write in the preface, "...challenges that software engineers face when modifying complex software systems...can be seen in the cost of modifying software...[which] can reach 70% of the total life-cycle cost." That number always leaves a strange taste in my mouth, since for any successful project I have encountered, the cost actually asymptotically approaches 100%.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;A. M. J. Hass, &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0321117662/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0321117662"&gt;Configuration Management Principles and Practice&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321117662&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;, 1st ed. Boston: Addison-Wesley, 2003.&lt;br /&gt;I am the first to claim that configuration management is one key to any reasonably successful project. However, I suspect that this is not the best book on the subject. The table of contents runs for 18 pages out of 350 or so with several interesting looking sections, but I do not see anything compelling overall. For example, Chapter 22 is "Getting started on configuration management---up to capability level 1" with subsections on "How to get started from nothing" and "First steps toward configuration management", but the next chapter, "Planning configuration management---up to capability level 2" seems to be all about a configuration management plan document, not what to do with the foundation from the previous chapter.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;E. Horowitz, et al., &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0929306414/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399373&amp;amp;creativeASIN=0929306414"&gt;Computer Algorithms&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0929306414&amp;amp;camp=217145&amp;amp;creative=399373" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt;, 2nd ed. Summit, NJ: Silicon Press, 2007.&lt;br /&gt;I have never seen this book before. If they had referenced &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0262033844/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0262033844"&gt;Introduction to Algorithms&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0262033844&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;&lt;/i&gt; by Comen, Leiserson, Rivest, and Stein, I would not have said anything at all; that is the book most people would think of, I believe. (Strange but true: that was the one computer science class I ever dropped. After a single class session.) Still, &lt;i&gt;Computer Algorithms&lt;/i&gt; looks to be a good book, although at 773 pages of algorithmy goodness, I suspect it's not light reading.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;IEEE-CS/ACM Joint Task Force on Software Engineering Ethics and Professional Practices. (1999, July 22, 2010). &lt;i&gt;&lt;a href="http://www.acm.org/about/se-code/"&gt;Software Engineering Code of Ethics and Professional Practice&lt;/a&gt;&lt;/i&gt; (Version 5.2).&lt;br /&gt;This one is free, reasonably short, and quick reading. The short version is:&lt;br /&gt;&lt;blockquote&gt;Software engineers shall commit themselves to making the analysis, specification, design, development, testing and maintenance of software a beneficial and respected profession. In accordance with their commitment to the health, safety and welfare of the public, software engineers shall adhere to the following Eight Principles:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;PUBLIC&lt;/b&gt; - Software engineers shall act consistently with the public interest.&lt;/li&gt;&lt;li&gt;&lt;b&gt;CLIENT AND EMPLOYER&lt;/b&gt; - Software engineers shall act in a manner that is in the best interests of their client and employer consistent with the public interest.&lt;/li&gt;&lt;li&gt;&lt;b&gt;PRODUCT&lt;/b&gt; - Software engineers shall ensure that their products and related modifications meet the highest professional standards possible.&lt;/li&gt;&lt;li&gt;&lt;b&gt;JUDGMENT&lt;/b&gt; - Software engineers shall maintain integrity and independence in their professional judgment.&lt;/li&gt;&lt;li&gt;&lt;b&gt;MANAGEMENT&lt;/b&gt; - Software engineering managers and leaders shall subscribe to and promote an ethical approach to the management of software development and maintenance.&lt;/li&gt;&lt;li&gt;&lt;b&gt;PROFESSION&lt;/b&gt; - Software engineers shall advance the integrity and reputation of the profession consistent with the public interest.&lt;/li&gt;&lt;li&gt;&lt;b&gt;COLLEAGUES&lt;/b&gt; - Software engineers shall be fair to and supportive of their colleagues.&lt;/li&gt;&lt;li&gt;&lt;b&gt;SELF&lt;/b&gt; - Software engineers shall participate in lifelong learning regarding the practice of their profession and shall promote an ethical approach to the practice of the profession.&lt;/li&gt;&lt;/ol&gt;&lt;/blockquote&gt;Learn it; love it; live it.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;S. H. Kan, &lt;a href="http://www.amazon.com/gp/product/0201729156/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=wwwcrsrnet-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399369&amp;amp;creativeASIN=0201729156"&gt;&lt;i&gt;Metrics and Models in Software Quality Engineering&lt;/i&gt;&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0201729156&amp;amp;camp=217145&amp;amp;creative=399369" style="border: none !important; margin: 0px !important;" width="1" /&gt;, 2nd ed. Boston: Addison-Wesley, 2002.&lt;br /&gt;This is another topic that I have never spent much time with. Looking at the table of contents, this text seems to offer a lot of interesting options, although I do not know if it goes into enough detail to actually implement them. Certainly, it cannot be worse than the "time to fix" numbers from various build and bug tracking tools. Chapters 15, 16, 17, and 18, on quality assessments and process improvement, do leave me somewhat concerned about the amount of snake oil involved.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;If you are not completely bored yet, you can go to the &lt;a href="http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for.html"&gt;second half&lt;/a&gt; of the list.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-2951372889504955161?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/2951372889504955161/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=2951372889504955161' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2951372889504955161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2951372889504955161'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/11/consolidated-reference-list-for-ieee.html' title='Consolidated Reference List for the IEEE Software Engineering Body of Knowledge'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-1202764363415481032</id><published>2011-11-17T10:29:00.000-06:00</published><updated>2011-11-17T10:36:26.181-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='link'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>Link o' the day: Roslyn and eval for C#</title><content type='html'>&lt;p&gt;Engaging in a journey of adventure and discovery, InfoWorld's &lt;a href="http://www.infoworld.com/d/application-development/microsofts-roslyn-reinventing-the-compiler-we-know-it-176671"&gt;Microsoft's Roslyn: Reinventing the compiler as we know it&lt;/a&gt; shows that C# developers are on the way to learning that eval in production code is not such a great idea.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;b&gt;So what is Roslyn good for?&lt;/b&gt;&lt;/p&gt;&lt;p&gt;The most obvious advantage of this kind of "deconstructed" compiler is that it allows the entire compile-execute process to be invoked from within .Net applications. Hejlsberg demonstrated a C# program that passed a few code snippets to the C# compiler as strings; the compiler returned the resulting IL assembly code as an object, which was then passed to the Common Language Runtime (CLR) for execution. Voilà! With Roslyn, C# gains a dynamic language's ability to generate and invoke code at runtime.&lt;/p&gt;&lt;p&gt;Put that same code into a loop that accepts input from the user, and you've created a fully interactive read-eval-print loop (REPL) console for C#, allowing you to manipulate and experiment with .Net APIs and objects in real time. With the Roslyn technology, C# may still be a compiled language, but it effectively gains all the flexibility and expressiveness that dynamic languages such as Python and Ruby have to offer.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;(One of the benefits of the difficulty of doing this sort of thing in C, for example, is that it's so painful that no one who would likely misuse it ever actually &lt;i&gt;does&lt;/i&gt;.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-1202764363415481032?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/1202764363415481032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1202764363415481032' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1202764363415481032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1202764363415481032'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/11/link-o-day-roslyn-and-eval-for-c.html' title='Link o&apos; the day: Roslyn and eval for C#'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-7388332769623486001</id><published>2011-11-12T12:15:00.001-06:00</published><updated>2011-11-13T22:31:41.753-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><title type='text'>IEEE Smart Tech Workshop, Huntsville</title><content type='html'>&lt;p&gt;Last weekend, I spent a couple of days going to the &lt;a href="http://www.ieee.org/membership_services/mga_maw.html"&gt;IEEE Smart Tech&lt;/a&gt; metro-area workshop in Huntsville, AL. The Metropolitan Area Workshop is a traveling conference sponsored by the IEEE Power and Energy Society, IEEE Computer Society, IEEE Communications Society, and IEEE-USA, with tracks on software engineering, wireless communications, smart power grid and, in our case, career assistance. In Huntsville, it was November 4-5 at the Von Braun Center.&lt;/p&gt;&lt;p&gt;Overall, the workshop was pretty decent. About 120 people attended; breakfast (pastries), lunch (boxed sandwiches), and a reception with enough food for dinner were provided; the price for IEEE members was $119; and there were no major catastrophes. (And I'm not just saying that because I set up the wireless access point that seems to have survived pretty well. Go &lt;a href="http://www.dd-wrt.com/site/index"&gt;DD-WRT&lt;/a&gt;!)&lt;/p&gt;&lt;h2&gt;Software engineering essentials&lt;/h2&gt;&lt;span style="float:right; margin:10px;border:thin solid black;"&gt;&lt;a href="http://www.crsr.net/images/ford-gibbs-1.2.png"&gt;&lt;img src="http://www.crsr.net/images/ford-gibbs-1.2-sm.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;Friday, I went to the "Software engineering essentials" track session, which was billed as:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Designed for software development professionals interested in confirming knowledge of industry-standard software practices.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Learn the principles, standards, and practices of software engineering to create more robust applications.&lt;/li&gt;&lt;li&gt;Review all 15 Knowledge Areas presented in the Guide to the Software Engineering Body of Knowledge (SWEBOK) with a special focus on principles and practices of Software Requirements, Design, Construction, and Testing.&lt;/li&gt;&lt;li&gt;Quizzes to test knowledge.&lt;/li&gt;&lt;li&gt;Course based on curriculum for the IEEE &lt;a href="http://www.computer.org/portal/web/certification/csdp"&gt;CSDP&lt;/a&gt; [Certified Software Development Professional] designation.&lt;/li&gt;&lt;li&gt;Increase your overall knowledge of the software development lifecycle and value to your company.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;The reality was not quite as expected. The class was taught by Dr. Tom Hilburn, Professor Emeritus of Software Engineering and Distinguished Engineering Professor at Embry-Riddle Aeronautical University. It briefly reviewed the following Knowledge Areas:&lt;ul&gt;&lt;li&gt;Software architecture and design&lt;/li&gt;&lt;li&gt;Software engineering process models&lt;/li&gt;&lt;li&gt;Software engineering economics&lt;/li&gt;&lt;li&gt;Professionalism and professional practice&lt;/li&gt;&lt;li&gt;Configuration management&lt;/li&gt;&lt;li&gt;Computing foundations, mathematical foundations, engineering foundations&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;There were more details on:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Requirements&lt;/li&gt;&lt;li&gt;Testing&lt;/li&gt;&lt;/ul&gt;&lt;span style="float:left; margin:10px;border:thin solid black;"&gt;&lt;a href="http://www.crsr.net/images/ford-gibbs-1.3.png"&gt;&lt;img src="http://www.crsr.net/images/ford-gibbs-1.3-sm.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/span&gt;&lt;p&gt;The workshop was focused on the &lt;a href="http://www.computer.org/portal/web/certification/csdp/prepare"&gt;CSDP Assessment Course&lt;/a&gt;. The detailed information about requirements and testing was presented by going through the assessment course sections on those KAs. As a result, the course was described by one participant as an "advertisement" for the assessment course.&lt;/p&gt;&lt;p&gt;As a result, it failed as both an introduction to the essentials of software engineering and as a preparation for the CSDP. Like the &lt;em&gt;Head First...&lt;/em&gt; books I have read, it was too focused on the assessment (in this case) to work as a tutorial on the given topic. And, because it spent so much time on the detailed topics, there was no time or effort put into trying to cover the scope of the CSDP.&lt;/p&gt;&lt;p&gt;The two images are taken from CMU/SEI technical report CMU/SEI-96-TR-004 / ESC-TR-96-004, &lt;a href="http://www.sei.cmu.edu/reports/96tr004.pdf"&gt;&lt;i&gt;A Mature Profession of Software Engineering&lt;/i&gt;&lt;/a&gt;, Gary Ford and Norman E. Gibbs, January 1996. The first, Figure 1-2, was was used by Dr. Hilburn as an illustration of a profession for software engineering; the second, Figure 1-3, is a little clearer about what is going on.&lt;/p&gt;&lt;h2&gt;Introduction to the smart grid&lt;/h2&gt;&lt;p&gt;The course I attended on Saturday was another kettle of fish. It's billing was:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Recommended for all technology professionals&lt;/p&gt;&lt;ul&gt;&lt;li&gt;NIST Conceptual Model and its domains and interfaces.&lt;/li&gt;&lt;li&gt;Smart metering.&lt;/li&gt;&lt;li&gt;The current state of smart grid applications and how these drive infrastructure requirements.&lt;/li&gt;&lt;li&gt;The integration of smart grid elements into utility operations.&lt;/li&gt;&lt;li&gt;Distribution automation as an enabling technology for smart grid.&lt;/li&gt;&lt;li&gt;Smart grid cyber security technology.&lt;/li&gt;&lt;li&gt;Smart grid standards framework and its challenges.&lt;/li&gt;&lt;li&gt;Overview of smart grid network communications and the data needed in/out of the network.&lt;/li&gt;&lt;li&gt;Monitoring equipment used by smart grid applications in the network to generate data for analysis and improving customer service.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;The class not only covered all that, it was entertaining to boot. The class was presented by &lt;a href="http://www.quanta-technology.com/staff/jerry-melcher"&gt;Jerry Melcher&lt;/a&gt; of Quanta Technology and included a stack of random factoids:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Storage per volume:&lt;/b&gt; Diesel 3300 joules/cc, lead acid battery 50 joules/cc, lithium ion batteries 150 joules/cc.&lt;/li&gt;&lt;li&gt;Storage on the customer side, rather than the utility side, is most efficient.&lt;/li&gt;&lt;li&gt;Economics today call for natural gas generators, or demand response technology.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Demand response&lt;/b&gt; systems look like generators to the utility. They act by reducing load from the consumer, providing the equivalent of low-cost generation for the provider. Demand response techniques are in widespread use for industrial consumers, but modern advanced metering technology and home area networking are needed to allow the utility to communicate with a non-industrial consumer's loads.&lt;/li&gt;&lt;li&gt;The expected &lt;b&gt;longevity&lt;/b&gt; of utility equipment is 40 years, something that is a surprise to most technology firms attempting to enter the business.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Quote&lt;/b&gt;: "The worst thing that we could allow to happen to our client was to let them talk us into a custom deployment."&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Unfortunately, since I know almost nothing about electrical power technology, most of the details of the class were not terribly useful for me.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-7388332769623486001?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/7388332769623486001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=7388332769623486001' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7388332769623486001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7388332769623486001'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/11/ieee-smart-tech-workshop-huntsville.html' title='IEEE Smart Tech Workshop, Huntsville'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-3599897356843115490</id><published>2011-11-10T19:16:00.000-06:00</published><updated>2011-11-12T12:13:48.670-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='system administration'/><category scheme='http://www.blogger.com/atom/ns#' term='tip'/><category scheme='http://www.blogger.com/atom/ns#' term='shell'/><title type='text'>ed is the standard text editor</title><content type='html'>&lt;p&gt;Yes, I know there are other ways of doing this kind of thing, particularly if you have &lt;a href="http://www.opscode.com/chef/"&gt;chef&lt;/a&gt; or &lt;a href="http://www.gnu.org/software/cfengine/"&gt;cfengine&lt;/a&gt; or whatever configured. Right here, right now, I don't. Yay.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.gnu.org/fun/jokes/ed.msg.html"&gt;ed&lt;/a&gt; has one very strong advantage over other editors: it is scriptable. No, not scriptable as in you can write code to modify how it works, scriptable as in it can be driven by a file full of commands, and thus can be run remotely, in a loop. So, if you need to edit a file on a mess of machines, to make the same change everywhere, remember, "ed is the standard text editor."&lt;/p&gt;&lt;p&gt;Create a script file containing the ed commands and the appropriate text:&lt;/p&gt;&lt;pre&gt;$ cat /tmp/edit &lt;br /&gt;g/^SSLRandomSeed connect/&lt;br /&gt;a&lt;br /&gt;&lt;br /&gt;# http://www.g-loaded.eu/2011/09/27/mod_gnutls-rc4-cipher-beast/&lt;br /&gt;SSLHonorCipherOrder on&lt;br /&gt;SSLCipherSuite !aNULL:!eNULL:!EXPORT:!DSS:!DES:RC4-SHA:RC4-MD5:ALL&lt;br /&gt;.&lt;br /&gt;w&lt;br /&gt;q&lt;br /&gt;$ &lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Then, use ssh to connect to the remote host and run the ed command on the file to be edited, reading standard input from the file. Trust me, using the separate file is easier than writing the commands in a here-document or something.&lt;/p&gt;&lt;pre&gt;$ for j in 01 02; do for k in b c; do ssh host$k$j ed /usr/local/httpd/conf/httpd.conf &lt; /tmp/edit; done; done&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3599897356843115490?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/3599897356843115490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3599897356843115490' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3599897356843115490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3599897356843115490'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/11/yes-i-know-there-are-other-ways-of.html' title='ed is the standard text editor'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-5535757501989614357</id><published>2011-11-04T02:56:00.000-05:00</published><updated>2011-11-04T02:56:00.031-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='notation'/><category scheme='http://www.blogger.com/atom/ns#' term='Knuth'/><category scheme='http://www.blogger.com/atom/ns#' term='link'/><category scheme='http://www.blogger.com/atom/ns#' term='Dijkstra'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>Link o' the day: Donald Knuth, Tony Hoare, and goto</title><content type='html'>&lt;p&gt;Hah! I found it!&lt;/p&gt;&lt;p&gt;Ok, I suspect I've found (and possibly blogged about) this before, but I like it, I think it is important and in any case, I just found it (again).&lt;/p&gt;&lt;p&gt;Following Edsger Dijkstra's &lt;a href="http://www.cs.utexas.edu/~EWD/ewd02xx/EWD215.PDF"&gt;Goto statement considered harmful&lt;/a&gt; [PDF], Donald Knuth wrote &lt;a href="http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.103.6084"&gt;Structured programming with go to statements&lt;/a&gt;, in which is written (p. 289):&lt;blockquote&gt;&lt;p&gt;&lt;b&gt;Axiomatics of Jumps&lt;/b&gt;&lt;/p&gt;&lt;p&gt;[...]&lt;/p&gt;&lt;p&gt;Just recently, however, Hoare has shown that there is, in fact, a rather simple way to give an axiomatic definition of &lt;b&gt;go to&lt;/b&gt; statements; indeed, he wishes quite frankly that it hadn't been quite so simple. For each label \(L\) in a program, the programmer should state a logical assertion \(\alpha(L)\) which is to be true whenever we reach \(L\). Then the axioms\[ \{\alpha(L)\}\ \textbf{go to}\ L\ \{false\} \]plus the rules of inference\[ \{\alpha(L)\}\ S\ \{P\}\ \vdash\ \{\alpha(L)\}\ L:S\ \{P\} \]are allowed in program proofs, and all properties of labels and &lt;b&gt;go to&lt;/b&gt;'s will follow if the \(\alpha(L)\) are selected intelligently. One must, of course, carry out the entire proof using the same assertion \(\alpha(L)\) for each appearance of the label \(L\), and some choices of assertions will lead to more powerful results than others.&lt;/p&gt;&lt;p&gt;Informally, \(\alpha(L)\) represents the desired state of affairs at label \(L\); this definition says essentially that a program is correct if \(\alpha(L)\) holds at \(L\) and before all "&lt;b&gt;go to&lt;/b&gt; \(L\)" statements, and that control never "falls through" a &lt;b&gt;go to&lt;/b&gt; statement to the following text. Stating the assertions \(\alpha(L)\) is analogous to formulating loop invariants. Thus, it is not difficult to deal formally with tortuous program structure if it turns out to be necessary; all we need to know is the "meaning" of each label.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Unfortunately, Knuth does not cite &lt;em&gt;where&lt;/em&gt; Hoare had just recently shown that.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5535757501989614357?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/5535757501989614357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5535757501989614357' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5535757501989614357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5535757501989614357'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/11/link-o-day-donald-knuth-tony-hoare-and.html' title='Link o&apos; the day: Donald Knuth, Tony Hoare, and goto'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-436915903590940999</id><published>2011-11-01T22:07:00.000-05:00</published><updated>2012-01-04T16:04:37.123-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>Systems programming</title><content type='html'>&lt;p&gt;People frequently come up to me and ask, "Bob, what is systems programming?" or, "Hey, Bob, what is a systems programming language?"&lt;/p&gt;&lt;p&gt;Those are more difficult questions than they appear. For part of the confusion, I blame John Ousterhout, the creator of the TCL programming language. TCL does not seem to get much use these days, but was one of the early, popular dynamic languages along with Perl, Python, and PHP. In "&lt;a href="http://www.tcl.tk/doc/scripting.html"&gt;Scripting: Higher Level Programming for the 21st Century&lt;/a&gt;", Ousterhout wrote, &lt;blockquote&gt;System programming languages were designed for building data structures and algorithms from scratch, starting from the most primitive computer elements such as words of memory. In contrast, scripting languages are designed for gluing: they assume the existence of a set of powerful components and are intended primarily for connecting components together.&lt;/blockquote&gt; I believe he was wrong on both counts. On the one hand, &lt;em&gt;all&lt;/em&gt; programming languages are, or should be, designed for building data structures and algorithms; to do otherwise severely limits what can be done with the language, even more so than not being Turing complete&lt;a href="#one"&gt;[1]&lt;/a&gt;. On the other hand, designing a language for connecting components primarily written in some other language is a losing game since most users will not create separate components.&lt;a href="#two"&gt;[2]&lt;/a&gt;&lt;a href="#three"&gt;[3]&lt;/a&gt;&lt;/p&gt;&lt;p&gt;What have Ousterhout's comments got to do with systems programming? His definition has, I believe, either led to (or been a result of the same cause of) many other languages such as Java being called "systems programming languages" when they rightly are not. The right question is not "What is the difference between systems programming languages and scripting languages", but "What is the difference between systems programming and applications programming?" To my mind, there is less real difference between TCL, Python, Perl, Ruby, and so on, and Java, Go, C#, etc., than between C and anything on that list.&lt;/p&gt;&lt;p&gt;So, what exactly is systems programming? It's hard to say. What are some of the characteristics of systems programming? That's an easier question. Systems programming usually involves the creation of software &lt;em&gt;for use by other software&lt;/em&gt;, not by humans. Systems programming is almost always about &lt;em&gt;managing resources&lt;/em&gt; for use by that other software. Systems programs may, and likely will, be built around complex data structures and algorithm and will also likely be built from the "most primitive computer elements" such as words of memory, if only because either&lt;ol&gt;&lt;li&gt;there is &lt;i&gt;nothing below them&lt;/i&gt; to create "less primitive" abstractions, or&lt;/li&gt;&lt;li&gt;it is absolutely vital that their performance, or memory, or some other footprint not directly related to whatever the ultimate task is, be optimized.&lt;/ol&gt;Operating system kernels are definitely systems programming. As are device drivers. Compilers? Not systems programs. Interpreters and virtual machines? Maybe. Embedded programming is a bit of a special case: many of the tasks involved in embedded software may be similar to the tasks involved in applications, but because the resources available to embedded software are so relatively expensive, their management becomes essential to every part of the device. On the other hand, technological advances have moved some of what was embedded development solidly into the applications arena; witness smart phones in the past few years.&lt;/p&gt; &lt;p&gt;Here's a rule of thumb I came up with back when it seemed necessary to choose between C and one of those other, applications languages for some task: Does the problem statement explicitly mention having to manage your own memory? If not, then you shouldn't be using C, and you probably aren't doing systems programming.&lt;/p&gt;&lt;p&gt;James Iry made a very insightful &lt;a href="http://james-iry.blogspot.com/2010/09/moron-why-c-is-not-assembly.html?rip_ritchie=true"&gt;observation&lt;/a&gt; about the nature of the C programming language:&lt;blockquote&gt;Alan Perlis famously said "a programming language is low level when its programs require attention to the irrelevant." What's relevant depends on the problem and the domain, so a corollary would be that a language that's at too high a level prevents paying attention to some of what is relevant for your needs.&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;I believe that statement is insightful (and it is the casus belli for this post) because it touches on exactly the key of systems programming. What would it mean to write a memory manager or garbage collector in a language that has garbage collection? How could you use a language for systems programming if you cannot manipulate a device whose control system is mapped into memory at a &lt;i&gt;specific&lt;/i&gt; location? Alternatively, why the stinking hell would you write an application in C if you didn't have to do some of those things?&lt;/p&gt;&lt;p&gt;I recently discovered a 2006 paper by Jonathan Shapiro, "&lt;a href="http://www.bitc-lang.org/docs/papers/PLOS2006-shap.pdf"&gt;Programming Language Challenges in Systems Codes: Why Systems Programmers Still Use C, and What to Do About It&lt;/a&gt;", describing the motives for &lt;a href="http://www.bitc-lang.org/"&gt;BitC&lt;/a&gt;, a systems programming language that integrates advances of the last thirty years of programming language technology. Shapiro provides a very idiosyncratic, but also very accurate description of systems programs:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Systems programs operate in constrained memory.&lt;/li&gt;&lt;li&gt;Systems programs are strongly driven by bulk I/O performance.&lt;/li&gt;&lt;li&gt;Performance matters. (And as a corollary, data representation matters.)&lt;/li&gt;&lt;li&gt;Systems programs retain state. (And as a corollary, user-managed storage is a requirement.)&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Shapiro's description of the first ("On a 32-bit [...] machine with [...] 64 gigabyte physical memory, it is extremely difficult to get the per-page book-keeping data structures to fit within a 0.5 gigabyte kernel virtual region."), second ("...the goal is to [perform] zero copies of that data [..., requiring] the creation of pointers that do not point to the beginning of an object [...or objects] multiply aliased in both the virtual and physical maps (e.g. by DMA) [...and sub-objects that] reference the storage of the original."), and third points ("...in the critical paths [...], the addition of only a few cache references — or worse, cache misses — in an inner loop can mean the difference between winning and losing customers") are largely what I mean by "resource management", specifically memory. Shapiro's fourth point is a little less obvious: &lt;blockquote&gt;The most common pattern in systems programs is event loops. While there is short-lived data within these processing loops, the pattern overall is that there are (relatively) large amounts of state that live for the duration of the event processing cycle. This tends to penalize the performance of automatic storage reclamation strategies. To make matters more interesting, there are caches. These update frequently enough that “old space” techniques may not perform well, but are large enough that scanning them can be quite expensive.&lt;/blockquote&gt; Consider that the event loops he is speaking about may continue for the up-time of the device. My original thought was that &lt;em&gt;implementing&lt;/em&gt; memory managers would be problematic in a language that provided automatic memory management; Shapiro is making the point that the &lt;em&gt;presence&lt;/em&gt; of automatic memory management may be detrimental.&lt;/p&gt;&lt;p&gt;Oh, and when someone comes up to me and asks one of those "Bob,...?" questions, I always answer the same way: "My name's not Bob."&lt;/p&gt;&lt;p&gt;[Edit: Added the link to and paragraphs about Jonathan Shapiro's paper. Thanks to Eli Gottlieb and "&lt;a href="http://decac.googlecode.com/files/Deca%20Thesis.pdf"&gt;The design and implementation of a modern systems programming language&lt;/a&gt;" for pointing it out (and &lt;a href="http://code.google.com/p/decac/"&gt;Deca&lt;/a&gt;). And my name's still not Bob.]&lt;/p&gt;&lt;p&gt;&lt;a name="one"&gt;&lt;b&gt;[1]&lt;/b&gt;&lt;/a&gt; For example, TCL itself  was designed with sole concern for glue capability, which leads to most of the reasons it has lost favor.&lt;/p&gt;&lt;p&gt;&lt;a name="two"&gt;&lt;b&gt;[2]&lt;/b&gt;&lt;/a&gt; TCL's glue capability created Tk, &lt;a href="http://www.nist.gov/el/msid/expect.cfm"&gt;Expect&lt;/a&gt;, and &lt;a href="http://www.aolserver.com/"&gt;AOLserver&lt;/a&gt;, but many more, complex, programs were simply written in TCL (likely using Tk) than were built by gluing other components together.&lt;/p&gt;&lt;p&gt;&lt;a name="three"&gt;&lt;b&gt;[3]&lt;/b&gt;&lt;/a&gt; Modulo command line shells such as sh, bash, etc., which are examples of programming languages as user interfaces. Also, the term "scripting" is much more appropriate for these languages. Complex applications in these languages are some of the most disturbing things I have ever seen.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-436915903590940999?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/436915903590940999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=436915903590940999' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/436915903590940999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/436915903590940999'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/11/systems-programming.html' title='Systems programming'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-3625330080982146839</id><published>2011-10-28T21:45:00.000-05:00</published><updated>2011-10-28T21:45:00.599-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Oracle JDBC API changes: things that make me sigh</title><content type='html'>&lt;p&gt;For reasons that escape me at the moment (something about support from Oracle, I think), we are having to upgrade the Oracle JDBC driver from 10.2.0.4 to 11.2.0.3. Ideally, this would be a simple, transparent change. But it isn't.&lt;/p&gt;&lt;p&gt;A co-worker quickly found an issue with the driver's handling of java.sql.Date and java.sql.Timestamp. Specifically, the previous driver would map SQL DATE columns to java.sql.Date, while the current driver maps SQL DATE columns to java.sql.Timestamp. The details are described by the Oracle JDBC faq, &lt;a href="http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#08_00"&gt;What is going on with DATE and TIMESTAMP?&lt;/a&gt; (Note: that entry describes the previous, 10.2.0.4 behavior as the "problem".)&lt;/p&gt;&lt;p&gt;The bottom line is that if you use &lt;code&gt;resultSet.getObject(i)&lt;/code&gt; then for a DATE column you will now get a java.sql.Timestamp object where you would previously get a java.sql.Date object. Also, if you use code like&lt;pre&gt;&lt;br /&gt;      switch (metaData.getColumnType(i))&lt;br /&gt;      {&lt;br /&gt;      case Types.DATE:&lt;br /&gt;        map.put(name, resultSet.getDate(i));&lt;br /&gt;        break;&lt;br /&gt;      case Types.TIMESTAMP:&lt;br /&gt;        map.put(name, resultSet.getTimestamp(i));&lt;br /&gt;        break;&lt;br /&gt;      ...&lt;br /&gt;&lt;/pre&gt;You will also get a java.sql.Timestamp instead of a java.sql.date, since the java.sql.Types mapping has changed as well.&lt;/p&gt;&lt;p&gt;Now, I don't know whether or not this is the Right Thing To Do. I don't actually care either way. But the change, even to fix a problem, just makes me want to sob quietly.&lt;/p&gt;&lt;p&gt;And the Java standard library's API is just as wacky as ever.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3625330080982146839?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/3625330080982146839/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3625330080982146839' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3625330080982146839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3625330080982146839'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/10/oracle-jdbc-api-changes-things-that.html' title='Oracle JDBC API changes: things that make me sigh'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-6120019064017099322</id><published>2011-10-24T23:46:00.000-05:00</published><updated>2011-10-24T23:46:00.114-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><title type='text'>Why I usually prefer the GPL</title><content type='html'>&lt;p&gt;&lt;em&gt;[I was busy this weekend with Peter Norvig and Sebastian Thrun's AI course and Bayesian probabilities, so I am reduced to recycling &lt;a href="http://www.reddit.com/r/programming/comments/llw0s/zed_shaw_on_gpl/c2u1nvz"&gt;reddit replies&lt;/a&gt;. But it is a topic I've been meaning to mention, so I do not feel too bad.]&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;blockquote&gt;&lt;a href="http://www.reddit.com/r/programming/comments/llw0s/zed_shaw_on_gpl/c2tusw2"&gt;Why does the license determine contributions?&lt;/a&gt;&lt;/blockquote&gt;&lt;/p&gt;&lt;p&gt;Once upon a time, there was an operating system that I'll call BSD UNIX. This OS was distributed under a very permissive license that basically allowed anyone do to anything they wanted with it, including redistributing it as a closed-source product. Which they did, creating a host of different, but somewhat similar operating systems, which I'll call AIX, HP-UX, SunOS, and IRIX (and a large stack of others, but those'll do for now). Each of these OS's grew lots of new features; bugs were fixed, changes were made, markets were differentiated, everyone was happy.&lt;/p&gt;&lt;p&gt;Until everyone noticed that software that ran on one of the pile didn't run on the others, leading to the creation of wonderful things like POSIX, imake, and autoconf. But that was a little bit too late and a little bit too little (and quite a bit too flaky), leading many people to the conclusion that all of these similar operating systems were a bizarrely painful sewer that they wanted nothing to do with. Market differentiation became market fragmentation, almost leading to the death of Unix operating systems.&lt;/p&gt;&lt;p&gt;In the mean time, the greatest developers in the world were working on BSD. Or so they thought, apparently, given that the license they had chosen didn't even have a strong suggestion that any changes that someone else made should be passed back to BSD. (Sure, if they weren't the best, they might want contributions, but since they were, obviously they could do a better job of new features and bug fixes, right?)&lt;/p&gt;&lt;p&gt;So, one day a young programmer comes along trying to decide if he wants to check out this new Linux thing or if he should spend some time with the newly un-encumbered BSD, which was a real Unix and obviously closely related to the OS's he was familiar with. Unfortunately, the new upstart supported shared libraries and FreeBSD didn't, because all of the descendant operating systems which did, did it in completely different ways and no one ever saw fit to contribute it back to the ancestor.&lt;/p&gt;&lt;p&gt;&lt;em&gt;[All characters and operating systems appearing in this work are fictitious. Any resemblance to real persons or operating systems, living or dead, running or panicked, is purely coincidental.]&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-6120019064017099322?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/6120019064017099322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=6120019064017099322' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6120019064017099322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6120019064017099322'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/10/why-i-usually-prefer-gpl.html' title='Why I usually prefer the GPL'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-5640299980804239418</id><published>2011-10-18T12:57:00.000-05:00</published><updated>2011-10-23T16:47:45.489-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>Quote o' the Day: Appel fanbois</title><content type='html'>Yes, I know it's three years old at this point, but I had to &lt;a href="http://www.reddit.com/r/programming/comments/6pjzm/want_to_write_a_compiler_just_read_these_two/c04j568"&gt;link to it&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Yeah, I agree with you. I've had it with all these Appel fanbois.&lt;/blockquote&gt;It's from a &lt;a href="http://www.reddit.com/r/programming/comments/6pjzm/want_to_write_a_compiler_just_read_these_two/"&gt;discussion about simplified introductions to compiler construction&lt;/a&gt; that included a recommendation for Andrew Appel's&amp;nbsp;&lt;i&gt;Modern Compiler Design in Java&lt;/i&gt;. Thank you, officemonkey.&lt;br /&gt;&lt;br /&gt;And there's a comment for anyone interested in the history of &lt;a href="http://www.reddit.com/r/programming/comments/6pjzm/want_to_write_a_compiler_just_read_these_two/c04jdpv"&gt;Go&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5640299980804239418?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/5640299980804239418/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5640299980804239418' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5640299980804239418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5640299980804239418'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/10/quote-o-day-appel-fanbois.html' title='Quote o&apos; the Day: Appel fanbois'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-3603878932130099942</id><published>2011-10-14T16:04:00.000-05:00</published><updated>2011-10-23T16:47:23.676-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><title type='text'>Quote o' the day: Dennis Ritchie</title><content type='html'>From &lt;a href="http://groups.google.com/group/net.unix-wizards/msg/1c9d2e4c341f9b41?pli=1"&gt;net.unix-wizards&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;I am not now, nor have I ever been, a member of the demigodic party.&lt;/blockquote&gt;&lt;br /&gt;From &lt;a href="http://cm.bell-labs.com/cm/cs/who/dmr/odd.html"&gt;Odd Comments and Strange Doings in Unix&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;"values of β will give rise to dom!"&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt; /*&lt;br /&gt;  * If the new process paused because it was&lt;br /&gt;  * swapped out, set the stack level to the last call&lt;br /&gt;  * to savu(u_ssav).  This means that the return&lt;br /&gt;  * which is executed immediately after the call to aretu&lt;br /&gt;  * actually returns from the last routine which did&lt;br /&gt;  * the savu.&lt;br /&gt;  *&lt;br /&gt;  * You are not expected to understand this.&lt;br /&gt;  */&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;"A substory: at some point several were sitting around working away. Bob Morris asked, almost conversationally, 'what are the arguments to ld?' Someone told him. We continued typing for the next minute, as a thought began to percolate, not quite to the top of the brain-- in other words, not quite fast enough. The terminal stopped echoing before anyone could stop and say 'Hold on Bob, what is it you're trying to do?'"&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3603878932130099942?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/3603878932130099942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3603878932130099942' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3603878932130099942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3603878932130099942'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/10/quote-o-day-dennis-ritchie.html' title='Quote o&apos; the day: Dennis Ritchie'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-4531863864722163633</id><published>2011-10-07T14:06:00.001-05:00</published><updated>2011-10-07T14:06:00.488-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='link'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>Link o' the Day: Everyone's first quantum program</title><content type='html'>&lt;a href="http://www.reddit.com/r/programming/comments/l16i4/qml_a_functional_quantum_programming_language/c2p2465"&gt;From the reddit thread&lt;/a&gt; on &lt;a href="http://sneezy.cs.nott.ac.uk/QML/"&gt;QML -- a functional quantum programming language&lt;/a&gt;, by erg0S4m: &lt;blockquote&gt;And the first program to be written has to be&lt;br /&gt;"Hello Worlds!"&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-4531863864722163633?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/4531863864722163633/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=4531863864722163633' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4531863864722163633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4531863864722163633'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/10/link-o-day-everyones-first-quantum.html' title='Link o&apos; the Day: Everyone&apos;s first quantum program'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-1267961615808230797</id><published>2011-10-05T19:09:00.002-05:00</published><updated>2011-10-05T19:13:38.615-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>Some notes on A Tour of Go</title><content type='html'>I have no particular comment about &lt;a href="http://go-tour.appspot.com/#12"&gt;this&lt;/a&gt;; my feelings (and the appearance of my eyebrows) should be reasonably obvious to reasonably regular readers. &lt;blockquote&gt;Inside a function, the := short assignment statement can be used in place of the short var declaration.&lt;br /&gt;(Outside a function, every construct begins with a keyword and the := construct is not available.)&lt;/blockquote&gt;"Outside of a dog, a book is a man's best friend. Inside of a dog, it's too dark to read." -- Groucho Marx.&lt;br /&gt;&lt;br /&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;Oddly, according to &lt;a href="http://go-tour.appspot.com/#20"&gt;20&lt;/a&gt;, the predicate of an if statement is not an expression:&lt;blockquote&gt;The if statement looks as it does in C or Java, except that the ( ) are gone (they are not even optional)....&lt;/blockquote&gt;Or so I assume, because in most languages, &lt;em&gt;expr&lt;/em&gt; is equivalent to &lt;em&gt;(expr)&lt;/em&gt;; the extra parentheses do nothing, but don't hurt anything either.&lt;br /&gt;&lt;br /&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;a href="http://go-tour.appspot.com/#21"&gt;What the&lt;/a&gt;...?!&lt;blockquote&gt;Like for, the if statement can start with a short statement to execute before the condition.&lt;pre&gt;if v := math.Pow(x, n); v &lt; lim {&lt;br /&gt;  return v&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br&gt;&lt;br&gt;In case I seem excessively negative, they have fixed one of C's major shortcomings: The &lt;a href="http://go-tour.appspot.com/#23"&gt;basic types&lt;/a&gt; specify their sizes.&lt;blockquote&gt;Go's basic types areboolstringint  int8  int16  int32  int64uint uint8 uint16 uint32 uint64 uintptrfloat32 float64complex64 complex128&lt;/blockquote&gt;&lt;br&gt;&lt;br&gt;The &lt;a href="http://go-tour.appspot.com/#29"&gt;syntax for map types&lt;/a&gt; is...odd.&lt;blockquote&gt;var m map[string]Vertex&lt;/blockquote&gt;&lt;br&gt;&lt;br&gt;&lt;a href="http://go-tour.appspot.com/#37"&gt;Functions&lt;/a&gt;... &lt;blockquote&gt;are full closures.The adder function returns a closure. Each closure is bound to its own sum variable.&lt;/blockquote&gt;For those of you misusing the term "closure", please stop. A closure is a implementation technique for lexically scoped functions, not a feature in itself.&lt;br&gt;&lt;br&gt;&lt;a href="http://go-tour.appspot.com/#40"&gt;Switch statements&lt;/a&gt;:&lt;blockquote&gt;A case body breaks automatically, unless it ends with a fallthrough statement.&lt;/blockquote&gt;Cry "Havoc!" and let slip the dogs of the inverse of the "break" war! Probably is a better default, though.&lt;blockquote&gt;&lt;pre&gt;today := time.LocalTime().Weekday&lt;br /&gt; switch time.Saturday {&lt;br /&gt; case today+0:&lt;br /&gt;  fmt.Println("Today.")&lt;br /&gt; case today+1:&lt;br /&gt;  fmt.Println("Tomorrow.")&lt;br /&gt; case today+2:&lt;br /&gt;  fmt.Println("In two days.")&lt;br /&gt; default:&lt;br /&gt;  fmt.Println("Too far away.")&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;today is an int (2 is Wednesday); time.Saturday is the int representing Saturday (6). The switch expression and the chosen case expression should match.&lt;blockquote&gt;&lt;pre&gt;switch {&lt;br /&gt; case t.Hour &lt; 12:&lt;br /&gt;     fmt.Println("Good morning!")&lt;br /&gt; case t.Hour &lt; 17:&lt;br /&gt;     fmt.Println("Good afternoon.")&lt;br /&gt; default:&lt;br /&gt;     fmt.Println("Good evening.")&lt;br /&gt; }&lt;/pre&gt;Switch without a condition is the same as switch true.&lt;/blockquote&gt;Unless the switch expression is missing, in which case the switch is equivalent to chained if statements.&lt;br&gt;&lt;br&gt;&lt;a href="http://go-tour.appspot.com/#61"&gt;Cooperative threads&lt;/a&gt;?&lt;blockquote&gt;&lt;pre&gt;package main&lt;br /&gt;&lt;br /&gt;import (&lt;br /&gt; "fmt"&lt;br /&gt;// "runtime"&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;func say(s string) {&lt;br /&gt; for i := 0; i &lt; 5; i++ {&lt;br /&gt;//  runtime.Gosched()&lt;br /&gt;  fmt.Println(s)&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;func main() {&lt;br /&gt; go say("world")&lt;br /&gt; say("hello")&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;yields&lt;blockquote&gt;&lt;pre&gt;hello&lt;br /&gt;hello&lt;br /&gt;hello&lt;br /&gt;hello&lt;br /&gt;hello&lt;/pre&gt;&lt;/blockquote&gt;&lt;br&gt;&lt;br&gt;Go language shows the influence of &lt;a href="http://cm.bell-labs.com/plan9/"&gt;Plan 9&lt;/a&gt;, which I suspect means a definite case of not-invented-here syndrome; it also seems to have a lot of local optimizations, choices that make sense for a particular case. Perl is another major language fond of local optimizations inflated to major features. I'm still not seeing a good reason to focus on Go rather than some of the alternatives. Your mileage may vary.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-1267961615808230797?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/1267961615808230797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1267961615808230797' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1267961615808230797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1267961615808230797'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/10/some-notes-on-tour-of-go.html' title='Some notes on A Tour of Go'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-3163307058238878502</id><published>2011-09-22T12:07:00.000-05:00</published><updated>2011-09-22T12:07:55.876-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><title type='text'>IEEE Smart Tech Metro Area Workshops: Huntsville</title><content type='html'>The two-day IEEE travelling Metro Area Workshop Series called &lt;a href="http://www.ieee.org/membership_services/mga_maw.html"&gt;IEEE Smart Tech&lt;/a&gt; is coming to Huntsville in November, the 4th and 5th. It looks like a pretty good deal: $99 for IEEE members, $179 for non-members (with a $20 discount for early registration) gets you breakfast and lunch &lt;a href="http://www.ieee.org/membership_services/mga_maw_agenda.html#sect1"&gt;both days&lt;/a&gt;, a Friday evening reception with hors d'oeuvres, &lt;a href="http://www.ieee.org/membership_services/mga_maw_agenda.html#sect6"&gt;plenary speakers&lt;/a&gt; (in Huntsville, Michael Griffen, former NASA Administrator), and two days of instruction at the scenic Von Braun Center. Oh, and two day-long courses in &lt;ul&gt;&lt;li&gt;Wireless Communications Engineering: Current Practice,&lt;/li&gt;&lt;li&gt;Introduction to Smart Grid, and&lt;/li&gt;&lt;li&gt;Software Engineering Essentials.&lt;/li&gt;&lt;/ul&gt;On Saturday, you can also attend a &lt;a href="http://www.ieee.org/membership_services/mga_maw_agenda.html#sect5"&gt;career assistance workshop&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'll be going to the &lt;a href="http://www.ieee.org/membership_services/mga_maw_agenda.html#sect3"&gt;Software Engineering Essentials&lt;/a&gt; presentation; while I may not care much for Software Engineering as a field in itself, I do believe software engineering techniques are a wee-bit useful when programming professionally. I'm torn between &lt;a href="http://www.ieee.org/membership_services/mga_maw_agenda.html#sect2"&gt;Introduction to Smart Grid&lt;/a&gt;, which just sounds like fun, and &lt;a href="http://www.ieee.org/membership_services/mga_maw_agenda.html#sect4"&gt;Wireless Communications Engineering&lt;/a&gt;, which is somewhat close to my network-protocol-ish heart.&lt;br /&gt;&lt;br /&gt;If you are in the Huntsville area around November 4th and 5th, or in Austin around October 21st, check it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3163307058238878502?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/3163307058238878502/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3163307058238878502' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3163307058238878502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3163307058238878502'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/09/ieee-smart-tech-metro-area-workshops.html' title='IEEE Smart Tech Metro Area Workshops: Huntsville'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-301784859389010523</id><published>2011-09-02T14:32:00.002-05:00</published><updated>2011-09-22T12:08:34.261-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='http'/><category scheme='http://www.blogger.com/atom/ns#' term='protocols'/><title type='text'>Changes over at www.crsr.net: nginx</title><content type='html'>I recently read &lt;a href="http://tumbledry.org/2011/08/31/9_million_hits_day_with_120"&gt;9 million hits/day with 120 megs RAM&lt;/a&gt;, in which Alex Micek benchmarked his small website with &lt;a href="http://blitz.io/"&gt;blitz.io&lt;/a&gt; and made some significant improvements to his performance. blitz.io is very easy to use, so I pointed it at &lt;a href="http://www.crsr.net"&gt;www.crsr.net&lt;/a&gt; and let 'er rip, with very disappointing results. www.crsr.net is a very simple, static file site that is (er, &lt;em&gt;was&lt;/em&gt;) served by Apache, and according to blitz.io I was taking approximately 300ms to serve a request. Ick.&lt;br /&gt;&lt;br /&gt;A while back, I looked at &lt;a href="http://nginx.net/"&gt;nginx&lt;/a&gt;, the allegedly faster web server, and considered replacing Apache with it. But I was lazy and didn't figure that nginx would really help much. Now, though, I had some incentive. I set up nginx on port 8080, pointing at the same www.crsr.net files, and fired off blitz.io again. Nginx took a factor of ten off Apache's results, and the configuration for replacing Apache was trivial.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.crsr.net/"&gt;www.crsr.net&lt;/a&gt; is now being served by nginx. Thanks, Igor Sysoev! And thanks, blitz.io!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-301784859389010523?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/301784859389010523/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=301784859389010523' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/301784859389010523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/301784859389010523'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/09/changes-over-at-wwwcrsrnet-nginx.html' title='Changes over at www.crsr.net: nginx'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-4569177431422384865</id><published>2011-08-24T00:18:00.003-05:00</published><updated>2011-09-01T14:57:35.651-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='link'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><title type='text'>Link o' the Day: Markets are Efficient If and Only If P = NP</title><content type='html'>This one from Jeff: a pointer to &lt;a href="http://www.aleph.se/andart/archives/2011/08/if_computer_scientists_are_right_you_can_make_money_on_the_market_if_economists_are_right_you_can_compute_fast.html"&gt;If computer scientists are right, you can make money on the market. If economists are right, you can compute fast,&lt;/a&gt; which is a reference to a paper to appear in &lt;i&gt;Algorithmic Finance&lt;/i&gt; by Philip Z. Maymin, &lt;a href="http://papers.ssrn.com/sol3/papers.cfm?abstract_id=1773169"&gt;Markets are Efficient If and Only If P = NP&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Economics and computer science have some things in common; they are the only two fields I know where exponential growth is a common situation, for one thing. Now, speaking as an innocent economic bystander, I have been convinced by the arguments in favor of the weak efficient market hypothesis, that "that future prices cannot be predicted by analyzing &lt;i&gt;prices&lt;/i&gt; from the past" (my emphasis), but significantly unconvinced by any of the arguments for any of the stronger forms, specifically the semi-strong (that the current price incorporates all publicly available information) and the strong form (that the current price incorporates all &lt;i&gt;private&lt;/i&gt; information). I am also a computer scientist, falling into the "I believe P is not equivalent to NP" camp. &lt;br /&gt;&lt;br /&gt;This paper seems to argue that even the &lt;i&gt;weak&lt;/i&gt; form is untenable, because the complexity of identifying an exploitable-inefficiency in the stream of market data requires exponential resources (while verifying an inefficiency requires only polynomial resources). As Anders Sandberg says, "In any case, it seems that the paper shows that computational complexity makes markets complex."&lt;br /&gt;&lt;br /&gt;I am not sure I buy the complete argument, particularly the second half, where Maymin attempts to encode the SAT-3 problem in market orders, but the paper does have an interesting perspective. Maybe those &lt;a href="http://en.wikipedia.org/wiki/Head_and_shoulders_(chart_pattern)"&gt;head-n-boulders&lt;/a&gt; charts are good for something.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-4569177431422384865?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/4569177431422384865/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=4569177431422384865' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4569177431422384865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4569177431422384865'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/08/link-o-day-markets-are-efficient-if-and.html' title='Link o&apos; the Day: Markets are Efficient If and Only If P = NP'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-5963306872359707464</id><published>2011-08-19T21:10:00.001-05:00</published><updated>2011-08-19T21:10:58.177-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='protocols'/><title type='text'>How the Internet Architecture Got its Hourglass Shape</title><content type='html'>And in other news, Constantine Dovrolis and Saamer Akhshabi at the School of Computer Science at the Georgia Institute of Technology &lt;quote&gt;"created an evolutionary model called EvoArch to study the emergence of the Internet’s hourglass structure,"&lt;/quote&gt; as described by &lt;a href="http://gtresearchnews.gatech.edu/hourglass-internet-architecture/"&gt;Staying in Shape: How the Internet Architecture Got its Hourglass Shape and What That Means for Future Internet Architectures&lt;/a&gt;. &lt;blockquote&gt;In the model, the architecture of the network changed with time as new protocols were created at different layers and existing protocols were removed as a result of competition with other protocols in the same layer.&lt;/blockquote&gt;&lt;br /&gt;Unfortunately, I am too busy to appreciate the success of the work, wondering if anyone explained to them that the &lt;a href="http://www.iab.org/wp-content/IAB-uploads/2010/11/hourglass-london-ietf.pdf"&gt;hourglass shape of the internet architecture&lt;/a&gt; was a deliberate design choice.&lt;br /&gt;&lt;br /&gt;The authors of the GIT press release wrote that, &lt;blockquote&gt;to ensure more diversity in the middle layers, EvoArch suggests designing protocols that are largely non-overlapping in terms of services and functionality so that they do not compete with each other.&lt;/blockquote&gt;I wonder exact kind of diversity and non-overlapping services they have in mind, considering the IP layer essentially provides universal connectivity.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5963306872359707464?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/5963306872359707464/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5963306872359707464' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5963306872359707464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5963306872359707464'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/08/how-internet-architecture-got-its.html' title='How the Internet Architecture Got its Hourglass Shape'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-8834581625221929059</id><published>2011-08-19T18:42:00.001-05:00</published><updated>2011-08-19T21:12:17.020-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='random'/><title type='text'>The Tappan Zee Bridge and software development</title><content type='html'>A recent &lt;a href="http://www.npr.org/blogs/money/2011/08/19/139749870/a-big-bridge-in-the-wrong-place"&gt;Planet Money podcast&lt;/a&gt; discussed the Tappan Zee Bridge and the perplexing issue of its location. The Tappan Zee is &lt;a href="http://maps.google.com/maps/ms?msid=210862890723521933918.0004aa199afc0c9981e5c&amp;msa=0&amp;ll=41.071069,-73.891296&amp;spn=0.310076,0.441513"&gt;located&lt;/a&gt; at one of the widest points on the Hudson river, and as a result after only a half-century or so is needing some significant replacement. If it were a few miles south, the river would be much narrower and the structure would be more sound.&lt;br /&gt;&lt;br /&gt;The bridge was built as part of the New York Thruway, one of the first controlled-access highways in the country, a grand scheme of then-governor Thomas Dewey. In order to build the rest of the Thruway, Dewey needed the revenue from the tolls on the bridge, and placing the bridge in a better location further south would have meant it was in the domain of the New York Port Authority, which has a monopoly on bridges, tunnels, and what-not within 25 miles of the Statue of Liberty. As a result, the Port Authority would have gotten the toll income, not the State of New York. So, the Tappan Zee is about twenty-five and a half miles from Liberty Island, is three and a half miles long, and is in need of repairs. But the Thruway exists, and seems to function admirably. (Or as much so as such can.)&lt;br /&gt;&lt;br /&gt;I am moved to this posting by the realization that many enterprise applications (since I am currently stuck in enterprise-land) are similarly constrained by the perversities of their environments. The best technical or engineering options are ruled out on seemingly irrational reasons, simply because there is no other way to get the damn thing &lt;em&gt;built&lt;/em&gt;. And getting the working application is more important than the subsequent pains involved in a below-best-standards mechanism.&lt;br /&gt;&lt;br /&gt;This sad fact is not limited to just the enterprise, though. Many of the failed projects I have been involved with were similarly constrained by non-technical decisions; in some cases, those were not even the reason the project failed.&lt;br /&gt;&lt;br /&gt;Next time, how H.P. Lovecraft's classic "The Shadow over Innsmouth" applies to modern software development.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-8834581625221929059?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/8834581625221929059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=8834581625221929059' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/8834581625221929059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/8834581625221929059'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/08/recent-planet-money-podcast-discussed.html' title='The Tappan Zee Bridge and software development'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-3756804344773443046</id><published>2011-07-09T11:34:00.004-05:00</published><updated>2011-08-21T12:54:57.512-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><title type='text'>User space file system comments</title><content type='html'>This is a comment I made on the Gluster blog, &lt;a href="http://www.gluster.com/2011/06/28/linus-torvalds-doesnt-understand-user-space-storage/comment-page-1/#comment-851"&gt;about a post&lt;/a&gt; on one of Linus Torvalds' &lt;a href="http://www.spinics.net/lists/linux-fsdevel/msg46078.html"&gt;incendiary comments&lt;/a&gt; on user-space filesystems.&lt;br /&gt;&lt;br /&gt;Way back in the dim mists of time, when microkernels were hot, Linus was having flame wars with AT, and the HURD actually sounded like it might someday be usable, I worked on the IBM microkernel project writing filesystem benchmarks. The idea was to build OS/2 (!), AIX, and other OS personalities on top of Mach, as multiple user-space servers.&lt;br /&gt;&lt;br /&gt;There were a lot of things wrong with the implementation (getpid() required a trip through Mach to an OS server), but the one thing that was a continual problem was filesystem performance. At one point, reading a page off disk was CPU bound. The issue wasn’t context switches, really, which can themselves be made arbitrarily fast, but carrying pages of data along with the context switch. The original copy-on-write turned out to be a pessimization—a very-well-written memcpy took a little less time to copy a page than the vm system took to set up the page share and copy-on-write. Then, if you eventually had to copy the page….&lt;br /&gt;&lt;br /&gt;I never figured out what was going on with the virtual memory system, but I’ve seen the same issue over and over. The MkLinux paper at the (1st and only, AFAIK) FSF conference is one of my favorite performance papers ever. The table showing performance comparisons looks good, as long as you didn’t notice that the top third was dhrystones; MkLinux didn’t actually slow the processor down. The Scout OS, a good research uK OS reported excellent performance, but didn’t separate user-space processes into different memory domains. The numbers reported by the security-enhanced follow-on, whose name I can’t remember but which did use multiple memory domains, was much worse. If you read between the lines of that paper comparing it to Linux, it would still have been a small multiple slower than Linux if it only used 2 protection domains instead of 3 for filesystem accesses.&lt;br /&gt;&lt;br /&gt;I’m as big a fan of user-level filesystems as anyone. They provide a neat and protected way of doing things that would otherwise not be as clean. On the other hand, to say “user space advantages far outweigh kernel space advantages” as a general rule is a pretty thoroughly blinkered view, too.&lt;br /&gt;&lt;br /&gt;Oh, and if you want the references to the MkLinux, Scout, and whatever-that-other-one-was papers, I’ll try to round them up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3756804344773443046?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/3756804344773443046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3756804344773443046' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3756804344773443046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3756804344773443046'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/07/this-is-comment-i-made-on-gluster-blog.html' title='User space file system comments'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-6137416425893936619</id><published>2011-07-04T19:09:00.003-05:00</published><updated>2011-07-11T11:24:38.212-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='toy problems'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><category scheme='http://www.blogger.com/atom/ns#' term='yeti'/><title type='text'>Snakes! On a Yeti!</title><content type='html'>Continuing on my Lisp kick, I have been reading &lt;i&gt;Programming Clojure&lt;/i&gt;, by Stuart Halloway. But that fact is a red herring for the moment; I have also been looking at a language called &lt;a href="http://mth.github.com/yeti/"&gt;Yeti&lt;/a&gt;. In order to take a pass at Yeti, I was casually trying to find a good sample program, which I finally found in &lt;i&gt;Programming Clojure&lt;/i&gt;: the Snake game from section 6.6.&lt;br /&gt;&lt;br /&gt;Yeti is a ML-style programming language for the JVM, featuring &lt;a href="http://en.wikipedia.org/wiki/Type_inference"&gt;Hindley-Milner type inference&lt;/a&gt; with &lt;a href="http://en.wikipedia.org/wiki/Structural_type_system"&gt;structurally-typed records&lt;/a&gt; and &lt;a href="http://caml.inria.fr/pub/docs/u3-ocaml/ocaml051.html"&gt;open variant types&lt;/a&gt; similar to O'Caml. It also provides reasonable access to Java and compiles to JVM bytecode. Yeti is similar to Scala, and &lt;a href="http://news.ycombinator.com/item?id=991828"&gt;andrewcooke&lt;/a&gt; posted what I believe is a good comparison on Hacker News; the key point is, "scala is baroque; yeti minimal."&lt;br /&gt;&lt;br /&gt;&lt;img style="float:right;margin:10px;border:thin solid black;" src="http://www.crsr.net/files/snake-small.png"&gt;As described by Halloway, "The snake game features a player-controlled snake that moves around a game grid hunting for an apple. When your snake eats an apple, it grows longer by a segment, and a new apple appears. If your snake reaches a certain length, you win. But if your snake crosses over its own body, you lose." The implementation is simple Swing and Halloway lists a number of other implementations for comparison:&lt;ul&gt;&lt;li&gt;Typed &lt;a href="http://planet.plt-scheme.org/package-source/dvanhorn/snake.plt/1/0/main.ss"&gt;Scheme&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Small and readable &lt;a href="http://www.plt1.com/1069/smaller-snake/"&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Tiny &lt;a href="http://www.plt1.com/1070/even-smaller-snake/"&gt;Clojure&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Partially verified in &lt;a href="http://www.ccs.neu.edu/home/cce/acl2/worm.html"&gt;ACL2&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Readable &lt;a href="http://www.ociweb.com/mark/programming/ClojureSnake.html"&gt;Clojure&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Bear in mind that this is literally my second Yeti program, following hello-world. I have fiddled with ML a bit and O'Caml a lot (for a while, it was my &lt;i&gt;official&lt;/i&gt; favorite programming language). I have also done rather a lot of Java lately, but only a small amount of Swing. Comments and suggestions are more than welcome.&lt;br /&gt;&lt;br /&gt;Given that, this is my version of Snake, snake.yeti.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;import java.util.Random;&lt;br /&gt;import java.awt: Color, Dimension, Graphics;&lt;br /&gt;import java.awt.event: ActionEvent, KeyEvent, ActionListener, KeyListener;&lt;br /&gt;import javax.swing: JFrame, JPanel, JOptionPane, Timer;&lt;/pre&gt;&lt;br /&gt;The program begins with a stack of imports, for the Java classes needed later. Each class can be imported separately or multiple classes from the same package can be listed together.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;A functional model&lt;/h3&gt;&lt;br /&gt;&lt;pre&gt;width = 75;&lt;br /&gt;height = 50;&lt;br /&gt;pointSize = 10;&lt;br /&gt;turnMillis = 75;&lt;br /&gt;winLength = 5;&lt;br /&gt;dirs =&lt;br /&gt;  [ KeyEvent#VK_LEFT :  {x = -1, y = 0},&lt;br /&gt;    KeyEvent#VK_RIGHT : {x = 1,  y = 0},&lt;br /&gt;    KeyEvent#VK_UP :    {x = 0,  y = -1},&lt;br /&gt;    KeyEvent#VK_DOWN :  {x = 0,  y = 1} ];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;These variables (in the mathematical sense) describe the width and height of the game grid, the conversion factor between the grid and pixels, the length of a game time step in milliseconds, and the number of segments required to win. (5 is a "boringly small number suitable for testing.") dirs is a map from numbers, given by static constants in the Java class KeyEvent, to points, as represented by a record or structure with x and y fields. dirs will be used to map key press events to changes in direction for the snake.&lt;br /&gt;&lt;br /&gt;Using the Yeti REPL, I captured Yeti's inference of dirs' type:&lt;br /&gt;&lt;pre&gt;&lt;i&gt;dirs is hash&amp;lt;number, {`x is number, `y is number}&gt; = [38:{x=0, y=-1},&lt;span style="color:blue"&gt;...elided...&lt;/span&gt;]&lt;/i&gt;&lt;br /&gt;&lt;/pre&gt;Similar to Java's Map&amp;lt;K,V&gt;, dirs is a map from number (Yeti's only numeric type, as far as I know), representing the key event values, to structurally-typed x,y pairs where each field is also a number.&lt;br /&gt;&lt;br /&gt;Because any key event will wind up looking in dirs, it is convenient to set a default for unrecognized key event values using setHashDefault. The first argument to setHashDefault is the map to be updated, while the second is an anonymous function (using Yeti's do notation) which ignores the argument (which is the unrecognized key) and always returns a null direction. (This will have the effect of pausing the game, if your snake has not eaten any apples. If your snake has eaten apples, you will lose immediately. But at least it doesn't throw any exceptions. Don't like it? Submit a bug report.)&lt;pre&gt;setHashDefault dirs do _: {x = 0, y = 0} done;&lt;/pre&gt;See below for more about functions and do.&lt;br /&gt;&lt;br /&gt;When I originally wrote this, I needed a couple of list utility functions, which I knew might be part of the standard library (the only documentation I had was a cached copy of the Yeti tutorial), or better expressed another way. The lists I am working with are the segments of the snake, which will not be terribly long, so I figured it did not matter much.&lt;br /&gt;&lt;pre&gt;&lt;em&gt;// butLast lst =&lt;br /&gt;//     if (length lst) &amp;lt;= 1 then [] else (head lst) :: (butLast (tail lst)) fi;&lt;br /&gt;&lt;br /&gt;// member? v lst =&lt;br /&gt;//     if empty? lst then false&lt;br /&gt;//     elif v == (head lst) then true&lt;br /&gt;//     else member? v (tail lst)&lt;br /&gt;//     fi;&lt;br /&gt;&lt;/em&gt;&lt;/pre&gt;butLast copies a list, excluding the last element. member? (and yes, Yeti allows the question mark in function names) tests whether the value v is an element of the list. Both written written using basic recursion, although Yeti is reputed to support better tail call optimization than Scala. Also, at the time, I could not figure out how to do pattern-matching destructuring on lists; instead, I used head, tail, length, and empty?.&lt;br /&gt;&lt;br /&gt;Fortunately, Madis &lt;a href="http://groups.google.com/group/yeti-lang/browse_thread/thread/ef716c7f4d681c15"&gt;pointed out&lt;/a&gt; &lt;ol&gt;&lt;li&gt;that the standard library does contain member?, known as "contains", and&lt;/li&gt;&lt;li&gt;that Yeti does do pattern-matching destructuring on lists, very cleanly.&lt;/li&gt;&lt;/ol&gt;&lt;pre&gt;butLast lst = case lst of&lt;br /&gt;    [_] : [];&lt;br /&gt;    h :: t : h :: butLast t;&lt;br /&gt;    _ : [];&lt;br /&gt;    esac;&lt;br /&gt;&lt;/pre&gt;The underscore '_' is an anonymous variable; a placeholder that requires a value in the destructuring, but which cannot be referenced later. In the first case the underscore indicates that the lst should have exactly one element; the third that &lt;em&gt;anything&lt;/em&gt; is acceptable. See below for more on case and destructuring.&lt;br /&gt;&lt;br /&gt;The basic form of a function definition in Yeti is &lt;pre&gt;&lt;em&gt;var = &lt;b&gt;do&lt;/b&gt; args... : expressions... &lt;b&gt;done&lt;/b&gt;&lt;/em&gt;&lt;/pre&gt;Since the form of the bare lambda expression in Yeti is &lt;pre&gt;&lt;em&gt;&lt;b&gt;do&lt;/b&gt; args... : expressions... &lt;b&gt;done&lt;/b&gt;&lt;/em&gt;&lt;/pre&gt;the basic form is just assigning a function expression to a variable. However, because function definitions are fairly common in Yeti code, there is a shorthand syntax illustrated by butLast: &lt;pre&gt;&lt;i&gt;fcn args... = expressions...&lt;/i&gt;&lt;/pre&gt;&lt;br /&gt;Another simple function is addPoints, which adds two x,y points together, producing another point.&lt;br /&gt;&lt;pre&gt;addPoints m n = {x = m.x + n.x, y = m.y + n.y};&lt;/pre&gt;The type of addPoints is &lt;pre&gt;&lt;i&gt;addPoints is {.x is number, .y is number}&lt;br /&gt; -&gt; {.x is number, .y is number}&lt;br /&gt; -&gt; {x is number, y is number} = &amp;lt;snake$addPoints&gt;&lt;/i&gt;&lt;/pre&gt;The type indicates that addPoints takes two structures containing (at least) numeric fields x and y and returns another structure with fields x and y. Because Yeti uses structural typing, the structure representing points is actually anonymous; &lt;em&gt;any&lt;/em&gt; structure containing suitable x and y fields could be added by addPoints.&lt;br /&gt;&lt;br /&gt;Because Yeti supports the ML-style definition of new operators, addPoints could have been written as &lt;pre&gt;// (.+.) m n = {x = m.x + n.x, y = m.y + n.y};&lt;/pre&gt;The resulting operator could be used like: &lt;pre&gt;&lt;em&gt;&gt; {x=4,y=3} .+. {x=1,y=1}&lt;br /&gt;{x=5, y=4} is {x is number, y is number}&lt;/em&gt;&lt;/pre&gt;I chose instead to remain consistent with Halloway's code.&lt;br /&gt;&lt;br /&gt;pointToScreenRec converts a game board point to a rectangle in screen coordinates for the display functions.&lt;br /&gt;&lt;pre&gt;pointToScreenRec pt =&lt;br /&gt;  { x = (pt.x * pointSize),&lt;br /&gt;    y = (pt.y * pointSize),&lt;br /&gt;    w = pointSize,&lt;br /&gt;    h = pointSize };&lt;br /&gt;&lt;/pre&gt;Once again, this function just builds and returns a new structure, with x, y, width, and height fields. The fields in the argument are accessed pretty traditionally, by a period followed by the field name.&lt;br /&gt;&lt;br /&gt;Yet another pseudo-constant is the random number generator used to place apples on the game board.&lt;br /&gt;&lt;pre&gt;r = new Random();&lt;/pre&gt;r's value will be an instance of java.util.Random, illustrating some of Yeti's Java integration.&lt;br /&gt;&lt;br /&gt;The next two functions create apples and snakes, both of which are also structures.&lt;br /&gt;&lt;pre&gt;createApple () =&lt;br /&gt;   { location = {x = r#nextInt(width), y = r#nextInt(height)},&lt;br /&gt;     color = new Color(210,50,90) };&lt;br /&gt;&lt;br /&gt;createSnake () =&lt;br /&gt;  { body = [{x = 1, y = 1}],&lt;br /&gt;    dir = {x = 1, y = 0},&lt;br /&gt;    color = new Color(15,160,70) };&lt;br /&gt;&lt;/pre&gt;Both also illustrate Java integration: the location of the apple is set randomly, by calling the nextInt(n) method. '#' replaces '.' in this use for Yeti. As well, the color of both apples and snakes is defined using java.awt.Color.&lt;br /&gt;&lt;br /&gt;createApple and createSnake take the special Yeti 'unit', (), as an argument. If they were defined without taking &lt;em&gt;something&lt;/em&gt; as an argument, they would be evaluated immediately as variables. The unit argument allows them to be defined as functions while simultaneously indicating that they do not take any &lt;em&gt;interesting&lt;/em&gt; arguments. () indicates both a type and the single, uninteresting value of that type.&lt;br /&gt;&lt;br /&gt;The function turn is simply used to replace the direction the snake is traveling. Originally, I wrote it as:&lt;br /&gt;&lt;pre&gt;&lt;em&gt;// turn snake newdir =&lt;br /&gt;//   { dir = newdir,&lt;br /&gt;//     body = snake.body,&lt;br /&gt;//     color = snake.color };&lt;br /&gt;&lt;/em&gt;&lt;/pre&gt;&lt;br /&gt;Madis also pointed out that Yeti &lt;ol&gt;&lt;li&gt;has a &lt;b&gt;with&lt;/b&gt; syntax to create a new structure based on an existing one, and&lt;/li&gt;&lt;li&gt;has a shortcut for associating variables and fields within a structure.&lt;/li&gt;&lt;/ol&gt;As a result, turn is:&lt;br /&gt;&lt;pre&gt;turn snake dir = snake with {dir};&lt;/pre&gt;The value of turn is a copy of the structure snake, with modifications. The form "{dir}" is equivalent to "dir = dir", meaning that the dir field in the new structure is given the value of the dir parameter.&lt;br /&gt;&lt;br /&gt;On the other hand, move is slightly more complex.&lt;br /&gt;&lt;pre&gt;move snake grow =&lt;br /&gt;  ( newhead = addPoints (head snake.body) snake.dir;&lt;br /&gt;    newbody = if grow then snake.body else (butLast snake.body) fi;&lt;br /&gt;    snake with {body = newhead :: newbody} );&lt;br /&gt;&lt;/pre&gt;newhead is computed to be the location of the snake's head plus the current direction. newbody is the either current body of the snake (if the snake is growing a new segment) or the current body without the terminal segment---if the snake is growing, it does so by extending at the head; if the snake is simply moving, a new head segment is added at one end while a tail segment is removed.&lt;br /&gt;&lt;br /&gt;Since the move function uses two local variables, newhead and newbody, and thus multiple expressions, the expressions in the function's body are enclosed in parentheses.&lt;br /&gt;&lt;br /&gt;This part of the program completes with a number of predicates used to determine if the player has won, lost, or if the snake can eat an apple.&lt;br /&gt;&lt;pre&gt;win? snake = length (snake.body) &gt;= winLength;&lt;br /&gt;&lt;br /&gt;headOverlapsBody? body = member? (head body) (tail body);&lt;br /&gt;&lt;br /&gt;lose? snake = headOverlapsBody? snake.body;&lt;br /&gt;&lt;br /&gt;eats? snake apple = (head snake.body) == apple.location;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Mutable state&lt;/h3&gt;&lt;br /&gt;The state of the game is kept in two mutable variables, snake and apple.&lt;br /&gt;&lt;pre&gt;var snake = createSnake ();&lt;br /&gt;var apple = createApple ();&lt;br /&gt;&lt;/pre&gt;The addition of the 'var' to the definition allows the two variables to be modified by assignment.&lt;br /&gt;&lt;br /&gt;There are three functions which update the state of the game.&lt;br /&gt;&lt;pre&gt;resetGame () =&lt;br /&gt;  ( snake := createSnake ();&lt;br /&gt;    apple := createApple () );&lt;br /&gt;&lt;br /&gt;updateDirection newdir = snake := turn snake newdir;&lt;br /&gt;&lt;br /&gt;updatePositions () =&lt;br /&gt;    if eats? snake apple&lt;br /&gt;    then apple := createApple ();&lt;br /&gt;         snake := move snake true;&lt;br /&gt;    else snake := move snake false&lt;br /&gt;    fi;&lt;br /&gt;&lt;/pre&gt;resetGame returns the game to something like it's initial state (remember, apple placement is random). updateDirection is a simple wrapper for turn, replacing the value of snake with a new snake traveling in the new direction. Finally, updatePositions tests whether the snake and apple are co-located; if they are, a new apple is created and the snake moves and grows a new segment; if they are not, the snake simply moves.&lt;br /&gt;&lt;br /&gt;resetGame and updatePositions also take the Yeti unit value to prevent the expression from being evaluated immediately. All three functions return unit:&lt;br /&gt;&lt;pre&gt;&lt;em&gt;&lt;br /&gt;resetGame is () -&gt; () = &amp;lt;snake$resetGame&gt;&lt;br /&gt;updateDirection is {`x is number, `y is number} -&gt; () = &amp;lt;snake$updateDirection&gt;&lt;br /&gt;updatePositions is () -&gt; () = &amp;lt;snake$updatePositions&gt;&lt;br /&gt;&lt;/em&gt;&lt;/pre&gt;Since () indicates both a type and the single value of that type, these typings indicate that these three functions do not return a useful value; any effect they have must be done via side effects, in this case by updating variables.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;GUI&lt;/h3&gt;&lt;br /&gt;In comparison with the mutable state, the GUI is a bit more complex and fancy, due to its integration with Java Swing.&lt;br /&gt;&lt;br /&gt;My first step is to define a type name, point, for the structure containing fields x and y.&lt;br /&gt;&lt;pre&gt;typedef point = { x is number, y is number };&lt;/pre&gt;The reason I did it is the next function, fillPoint.&lt;br /&gt;&lt;pre&gt;fillPoint g pt c is ~Graphics -&gt; point -&gt; ~Color -&gt; () =&lt;br /&gt;   ( {x,y,w,h} = pointToScreenRec pt;&lt;br /&gt;     g#setColor(c);&lt;br /&gt;     g#fillRect(x,y,w,h) );&lt;br /&gt;&lt;/pre&gt;fillPoint is the first function I have used that needs a type specification. It takes an argument, g, which is a Graphics context (marked with a '~' to indicate it is a raw Java class instead of a Yeti type), a point structure, and a Java Color. This function needs the type declaration because Yeti's type inference is unable to do anything with g, since the only thing I do is call the methods setColor and fillRect. fillPoint is also the first function in which I have used a destructuring bind, which picks apart the structure returned by pointToScreenRec into variables x, y, w, and h. These variables are then used to provide the necessary arguments to Graphics#fillRect. That statement also makes use of the "{x}" == "{x=x}" equivalence shortcut.&lt;br /&gt;&lt;br /&gt;I used the point type definition to clean up the fillPoint type declaration. Because it acts as a simple alias, the type of fillPoint reported by the REPL is&lt;br /&gt;&lt;pre&gt;&lt;em&gt;fillPoint is ~java.awt.Graphics -&gt; {`x is number, `y is number} -&gt; ~java.awt.Color -&gt; () = &amp;lt;snake$fillPoint&gt;&lt;/em&gt;&lt;/pre&gt;&lt;br /&gt;Next, I have a bug. I left it in the code because it is instructive.&lt;br /&gt;&lt;pre&gt;paintApple g a = fillPoint g apple.location apple.color;&lt;/pre&gt;paintApple draws an apple using fillPoint, but it should take graphics context and the apple as an argument. Instead, it is using the apple variable. I noticed the type of paintApple is&lt;br /&gt;&lt;pre&gt;&lt;em&gt;paintApple is ~java.awt.Graphics -&gt; 'a -&gt; () = &amp;lt;snake$paintApple&gt;&lt;/em&gt;&lt;/pre&gt;The interesting part is the 'a; that is a raw type variable. Type variables appear with parametric polymorphism, as in Java's List&amp;lt;t&gt; or the equivalent Yeti's list&lt;'a&gt;. However, in this case it indicates something seriously wrong with paintApple since a type variable can take any type. Specifially in this code, it means that the parameter a is never used.&lt;br /&gt;&lt;br /&gt;paintSnake does not have the bug.&lt;br /&gt;&lt;pre&gt;paintSnake g s =&lt;br /&gt;    for s.body do segment: fillPoint g segment s.color done;&lt;br /&gt;&lt;/pre&gt;Its type is &lt;pre&gt;&lt;em&gt;paintSnake is ~java.awt.Graphics&lt;br /&gt; -&gt; {.body is list?&lt;{`x is number, `y is number}&gt;, .color is ~java.awt.Color}&lt;br /&gt; -&gt; () = &amp;lt;snake$paintSnake&gt;&lt;/em&gt;&lt;/pre&gt;&lt;br /&gt;paintSnake also shows a &lt;b&gt;for&lt;/b&gt; loop, the use of the function &lt;b&gt;for&lt;/b&gt; to iterate through the segments of the snake, calling the anonymous function &lt;b&gt;do&lt;/b&gt;...&lt;b&gt;done&lt;/b&gt; to draw each segment.&lt;br /&gt;&lt;br /&gt;At this point things get a little hairy. To display the game board and interact with the player, I need to create a subclass of JPanel and an implementation of ActionListener and KeyListener. That is, I need GamePanel.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class GamePanel(JFrame frame) extends JPanel, ActionListener, KeyListener&lt;br /&gt;    void paintComponent(Graphics g)&lt;br /&gt;        super#paintComponent(g);&lt;br /&gt;        g#clearRect(0,0,(width+1) * pointSize,(height+1)*pointSize);&lt;br /&gt;        paintSnake g snake;&lt;br /&gt;        paintApple g apple,&lt;br /&gt;&lt;br /&gt;    void actionPerformed(ActionEvent e)&lt;br /&gt;        updatePositions ();&lt;br /&gt;        if lose? snake&lt;br /&gt;        then resetGame();&lt;br /&gt;             JOptionPane#showMessageDialog(frame,"You lose!")&lt;br /&gt;        elif win? snake&lt;br /&gt;        then resetGame();&lt;br /&gt;             JOptionPane#showMessageDialog(frame,"You win!")&lt;br /&gt;        fi;&lt;br /&gt;        this#repaint(),&lt;br /&gt;&lt;br /&gt;    void keyPressed(KeyEvent e)&lt;br /&gt;        updateDirection dirs.[e#getKeyCode()],&lt;br /&gt;&lt;br /&gt;    Dimension getPreferredSize()&lt;br /&gt;        new Dimension((width + 1) * pointSize,&lt;br /&gt;                      (height + 1) * pointSize),&lt;br /&gt;&lt;br /&gt;    void keyReleased(KeyEvent e),&lt;br /&gt;&lt;br /&gt;    void keyTyped(KeyEvent e)&lt;br /&gt;end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;GamePanel is a Java class defined in Yeti code. The methods it implements are paintComponent (JPanel), actionPerformed (ActionListener), keyPressed (KeyListener), getPreferredSize (JPanel), keyReleased (KeyListener), and keyTyped (KeyListener).&lt;br /&gt;&lt;br /&gt;paintComponent clears the game board's window and draws the snake and the apple. It also shows how to make a call to a superclass' method, the call to the superclass' paintComponent.&lt;br /&gt;&lt;br /&gt;actionPerformed is called based on a timer; it updates positions and tests whether the win or loss conditions are satisfied and completes by updating the game board.&lt;br /&gt;&lt;br /&gt;keyPressed is used to change the direction of the snake, based on arrow-key input. getPreferredSize returns a Dimension containing the on-screen size of the game board. keyReleased and keyTyped are ignored and do nothing.&lt;br /&gt;&lt;br /&gt;An instance of GamePanel is created using the gamePanel function, which accepts a JFrame as the constructor argument.&lt;br /&gt;&lt;pre&gt;gamePanel frame = new GamePanel(frame);&lt;/pre&gt;Like Scala, Yeti uses an implicit constructor scheme, where the arguments to the constructor are stored as members of the instance. Unlike Scala, &lt;a href="http://maniagnosis.crsr.net/2009/01/scala-problem-1.html"&gt;bizarre do-what-I-mean semantics&lt;/a&gt; do not seem to be involved.&lt;br /&gt;&lt;br /&gt;Finally, the game function itself is relatively simple imperative code:&lt;br /&gt;&lt;pre&gt;game () =&lt;br /&gt;  ( frame = new JFrame("Snake");&lt;br /&gt;    panel = gamePanel frame;&lt;br /&gt;    timer = new Timer(turnMillis,panel);&lt;br /&gt;    panel#setFocusable(true);&lt;br /&gt;    panel#addKeyListener(panel);&lt;br /&gt;    frame#add(panel);&lt;br /&gt;    frame#pack();&lt;br /&gt;    frame#setVisible(true);&lt;br /&gt;    timer#start() );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Endgame&lt;/h3&gt;&lt;br /&gt;To play the game, fire up the Yeti REPL, load the module, and invoke game:&lt;br /&gt;&lt;pre&gt;$ java -jar yeti.jar&lt;br /&gt;Yeti REPL.&lt;br /&gt;&lt;br /&gt;&gt; load snake&lt;br /&gt;&lt;span style="color:blue"&gt;...elided...&lt;/span&gt;&lt;br /&gt;&gt; game ()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Miscellanea&lt;/h3&gt;&lt;br /&gt;The remaining part of Yeti which I explored, but did not ultimately use in the snake game, is open variant types. To use these, the record returned by createApple could be tagged with 'Apple':&lt;br /&gt;&lt;pre&gt;// createApple () = Apple {&lt;br /&gt;//              location = {x = r#nextInt(width),&lt;br /&gt;//                          y = r#nextInt(height)},&lt;br /&gt;//              color = new Color(210,50,90),&lt;br /&gt;//              };&lt;br /&gt;&lt;/pre&gt;Using that, I could define a single function, paint, to replace paintApple and paintSnake:&lt;br /&gt;&lt;pre&gt;// paint g object =&lt;br /&gt;//     case object of&lt;br /&gt;//         Snake s : for s.body do segment: fillPoint g segment s.color done;&lt;br /&gt;//         Apple a : fillPoint g a.location a.color;&lt;br /&gt;//     esac;&lt;br /&gt;&lt;/pre&gt;The type of paint is:&lt;br /&gt;&lt;pre&gt;&lt;em&gt;paint is&lt;br /&gt;    ~java.awt.Graphics&lt;br /&gt; -&gt;   Apple {.color is ~java.awt.Color, .location is {`x is number, `y is number}}&lt;br /&gt;    | Snake {.body is list?&lt;{`x is number, `y is number}&gt;, .color is ~java.awt.Color}&lt;br /&gt; -&gt; () = &amp;lt;snake$paint&gt;&lt;/em&gt;&lt;/pre&gt;The second argument of paint is &lt;em&gt;either&lt;/em&gt; an appropriate structure tagged with Apple or an appropriate structure tagged with Snake; the tag  determines which branch is expected.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;br /&gt;I like Yeti. It seems a pretty nice representative of the ML family on the JVM. The integration with Java seems to be a little clunky, but not irritatingly so.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://mth.github.com/yeti/"&gt;Yeti&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://chrisichris.wordpress.com/category/yeti/"&gt;Chrisichris's Blog posts on Yeti&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://linux.ee/~mzz/yeti/intro.html"&gt;A short introduction to Yeti&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://groups.google.com/group/yeti-lang?pli=1"&gt;The yeti-lang mailing list&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.crsr.net/files/snake.yeti"&gt;My snake code&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Madis made several excellent suggestions about this posting (and code changes to yeti). Thanks!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-6137416425893936619?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/6137416425893936619/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=6137416425893936619' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6137416425893936619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6137416425893936619'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/07/snakes-on-yeti.html' title='Snakes! On a Yeti!'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-2968068515923011272</id><published>2011-07-01T10:27:00.000-05:00</published><updated>2011-07-01T10:27:43.612-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><title type='text'>Quote o' the day: Interpretive dance as a user interface</title><content type='html'>From a &lt;a href="http://radar.oreilly.com/2011/06/netflix-platforms-apps-webkit-testing.html"&gt;reddit discussion&lt;/a&gt; of &lt;a href="http://radar.oreilly.com/2011/06/netflix-platforms-apps-webkit-testing.html"&gt;Netflix user interfaces&lt;/a&gt;, &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;netflix, on Xbox, could use a lot of work.... -- &lt;b&gt;theDrWho&lt;/b&gt;&lt;br /&gt;I think the input device is the major limiting factor there. -- &lt;b&gt;recursive&lt;/b&gt;&lt;br /&gt;The Kinect should solve that problem. Of course, you might have to take a few classes in jazz dancing to use the UI. -- &lt;b&gt;jadero&lt;/b&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-2968068515923011272?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/2968068515923011272/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=2968068515923011272' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2968068515923011272'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2968068515923011272'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/07/quote-o-day-interpretive-dance-as-user.html' title='Quote o&apos; the day: Interpretive dance as a user interface'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-8624493720467516780</id><published>2011-06-22T04:54:00.002-05:00</published><updated>2011-07-24T11:52:05.597-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='comics'/><category scheme='http://www.blogger.com/atom/ns#' term='link'/><title type='text'>Link o' the day: Greatest xkcd ever!</title><content type='html'>Forget the map of Internet users scaled by bandwidth-donut consumption product. This is it:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://xkcd.com/908/"&gt;&lt;img width="740" height="236" src="http://imgs.xkcd.com/comics/the_cloud.png" title="There's planned downtime every night when we turn on the Roomba and it runs over the cord." style="border:thin solid black; padding:10px;"&gt;&lt;/img&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-8624493720467516780?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/8624493720467516780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=8624493720467516780' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/8624493720467516780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/8624493720467516780'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/06/link-o-day-greatest-xkcd-ever.html' title='Link o&apos; the day: Greatest xkcd ever!'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-6674638984622932700</id><published>2011-06-17T22:53:00.003-05:00</published><updated>2011-06-18T16:29:22.762-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='notation'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><category scheme='http://www.blogger.com/atom/ns#' term='data structure'/><title type='text'>Some Lisp suggestions</title><content type='html'>I am most definitely not a Lisp guru, but after finishing &lt;em&gt;Land of Lisp&lt;/em&gt;, I have a couple of suggestions that might reduce the general imperviousness of Lisp code. In my opinion, most of the antipathy towards Lisp's parentheses is a red herring; those parentheses merely express the structure of the code---which is present but implicit in any code---while the actual problem is that the code is bad, a problem which is exacerbated by the explicit structure.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;defstruct is your friend! Use it!&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Allegedly, &lt;a href="http://en.wikipedia.org/wiki/J._B._S._Haldane"&gt;J.B.S. Haldane&lt;/a&gt; once described what a lifetime of biology had taught him about God as "an inordinate fondness for beetles". One thing that frequently bothers me about code in untyped languages in general, but specifically in Lisp, is an excessive focus on &lt;em&gt;representations&lt;/em&gt; of data, rather than the &lt;em&gt;structure&lt;/em&gt; of data. Rather than identifying and building on an abstract data structure, the programmer will simply put the components of data into a hash table or a list and access the components using raw hash or list functions.&lt;br /&gt;&lt;br /&gt;For example, this is a function for &lt;i&gt;Land of Lisp&lt;/i&gt;; below I rewrote the function using &lt;b&gt;defstruct&lt;/b&gt; to reify the game tree (&lt;b&gt;tree-node&lt;/b&gt;) and moves (&lt;b&gt;attacking-move&lt;/b&gt; and &lt;b&gt;passing-move&lt;/b&gt;). I also slapped some color on the two functions to emphasize the corresponding functions.&lt;br /&gt;&lt;pre&gt;(defun limit-tree-depth (tree depth)&lt;br /&gt;  (&lt;span style="color:#00BB00"&gt;list&lt;/span&gt; (&lt;span style="color:#000088"&gt;car&lt;/span&gt; tree) &lt;br /&gt;        (&lt;span style="color:#000088"&gt;cadr&lt;/span&gt; tree) &lt;br /&gt;        (if (zerop depth)&lt;br /&gt;            (lazy-nil)&lt;br /&gt;            (lazy-mapcar (lambda (move)&lt;br /&gt;                            (&lt;span style="color:#660000"&gt;list&lt;/span&gt; (&lt;span style="color:#777700"&gt;car&lt;/span&gt; move) &lt;br /&gt;                                  (limit-tree-depth (&lt;span style="color:#777700"&gt;cadr&lt;/span&gt; move) (1- depth))))&lt;br /&gt;                         (&lt;span style="color:#000088"&gt;caddr&lt;/span&gt; tree)))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(defun limit-tree-depth (tree depth)&lt;br /&gt;  (labels ((limit-depth-move (move)&lt;br /&gt;             (let* ((next-tree (limit-tree-depth (&lt;span style="color:#777700"&gt;get-tree&lt;/span&gt; move) (1- depth))))&lt;br /&gt;               (if (&lt;span style="color:#660000"&gt;passing-move-p&lt;/span&gt; move)&lt;br /&gt;                   (&lt;span style="color:#660000"&gt;make-passing-move&lt;/span&gt; :tree next-tree)&lt;br /&gt;                   (&lt;span style="color:#660000"&gt;make-attacking-move&lt;/span&gt; :src (&lt;span style="color:#777700"&gt;attacking-move-src&lt;/span&gt; move)&lt;br /&gt;                                        :dst (&lt;span style="color:#777700"&gt;attacking-move-dst&lt;/span&gt; move)&lt;br /&gt;                                        :tree next-tree)))))&lt;br /&gt;    (&lt;span style="color:#00BB00"&gt;make-tree-node&lt;/span&gt; :player (&lt;span style="color:#000088"&gt;tree-node-player&lt;/span&gt; tree)&lt;br /&gt;                    :board (&lt;span style="color:#000088"&gt;tree-node-board&lt;/span&gt; tree)&lt;br /&gt;                    :moves (if (zerop depth)&lt;br /&gt;                               (lazy-nil)&lt;br /&gt;                               (lazy-mapcar #'limit-depth-move&lt;br /&gt;                                            (&lt;span style="color:#000088"&gt;tree-node-moves&lt;/span&gt; tree))))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, the first function is markedly shorter than the second (although part of that is my apparent fondness for large names). However, unless you are fond of remembering that the &lt;b&gt;car&lt;/b&gt; of one kind of list identifies a player in a node of the game tree, while the list of subsequent moves is the &lt;b&gt;caddr&lt;/b&gt;, and the &lt;b&gt;car&lt;/b&gt; of another kind of list identifies the aggressor and defender of a move (and implicitly whether it is an attacking move or a passing move), I respectfully suggest that the second might be preferable. In fact, a significant chunk of the length difference is that I have used different structures for the passing move (which only has the subsequent game tree node) and the attacking move (which also has the attacking and defending board positions).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Abstraction is good, too.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;There are those in the functional programming community who identify &lt;i&gt;function&lt;/i&gt; with &lt;i&gt;abstraction&lt;/i&gt;. If I understand them correctly, they use the two words interchangeably. I believe that is a very grave mistake, since it would mean that the &lt;b&gt;lambda&lt;/b&gt; expression in the first example is, in some sense, the same as the use of the &lt;b&gt;limit-depth-move&lt;/b&gt; function. As for me, if I had to identify abstraction with a single technique, I would link it to &lt;i&gt;naming&lt;/i&gt;; to my mind, the first &lt;b&gt;lambda&lt;/b&gt; expression is an implementation detail that clutters up the building of the moves of the new game tree node, while the second version (as hideous as the &lt;b&gt;labels&lt;/b&gt; construct is) provides the function as an identifiable, named, meaningful chunk.&lt;br /&gt;&lt;br /&gt;If you compare typical Lisp code with typical code in a language from the ML family, I think you'll find that Lisp code has more functions built of multiple steps, and greater nesting, than the ML code; ML code will more likely use &lt;b&gt;let&lt;/b&gt; or &lt;b&gt;where&lt;/b&gt; to break out identifiable functions and values. As a result, in my opinion, the ML code is consistently easier to read.&lt;br /&gt;&lt;br /&gt;After some further thought, I suspect the emphasis on representations is a result of working top-down to design the program. Further, I am almost positive that the more complex code and lack of abstraction are also a symptom of the same approach. Top-down design tends to be fine down to a certain level, at which point the code appears "simple enough". Further work, however, makes the code more complex but without redesigning the existing structure. A bottom-up approach almost calls for the identification of abstractions for working with the next level of code. (On the other hand, a bottom-up approach usually requires more work, since it involves traveling towards a destination without being sure of the best direction. Also, it can suffer from the same problem at the &lt;i&gt;other&lt;/i&gt; end of the program, where the higher structure of the code seems simple enough until it needs elaboration to complete the solution.)&lt;br /&gt;&lt;br /&gt;I do not want to pick on &lt;i&gt;Land of Lisp&lt;/i&gt; unfairly. It is a very good, and entertaining, book. The code examples are, overall, very clean and nice. However, reading it reminded me of the difficulties I have had with other Lisp (and other dynamically-typed code) in the past.&lt;br /&gt;&lt;br /&gt;[Edit: Typo and second-to-last paragraph fixed due to comments from reddit. Thanks!]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-6674638984622932700?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/6674638984622932700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=6674638984622932700' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6674638984622932700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6674638984622932700'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/06/some-lisp-suggestions.html' title='Some Lisp suggestions'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-2811393013862295222</id><published>2011-06-10T11:35:00.001-05:00</published><updated>2011-06-10T11:38:36.161-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='link'/><category scheme='http://www.blogger.com/atom/ns#' term='protocols'/><title type='text'>Link o' the Day: protolol</title><content type='html'>&lt;blockquote&gt;“There. There is. There is nothing. There is nothing funny about path MTU detection.”&lt;br /&gt;— &lt;a href="http://protolol.com/"&gt;protolol&lt;/a&gt;&lt;/blockquote&gt;&lt;br /&gt;Courtesy of Corey.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-2811393013862295222?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/2811393013862295222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=2811393013862295222' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2811393013862295222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2811393013862295222'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/06/link-o-day-protolol.html' title='Link o&apos; the Day: protolol'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-124514150322275073</id><published>2011-06-07T16:38:00.000-05:00</published><updated>2011-06-07T16:38:48.715-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='shell'/><title type='text'>Shell scripting fun: pdfsplit</title><content type='html'>Like various other people, I have been irritated by the problems with viewing two-column PDF files on a Kindle. Yesterday, however, I ran across &lt;a href="http://dmwit.com/pdfsplit/"&gt;pdfsplit&lt;/a&gt;, which made me decide to do something about it.&lt;br /&gt;&lt;br /&gt;I downloaded the package, which is Cabal-ized Haskell (!), and like my other adventures with Cabal, it failed to build. Naturally, I took a peek at the code, and found it to be a very simple script that used some libraries I apparently don't have (or have and don't know it; or something).&lt;br /&gt;&lt;br /&gt;I like writing Haskell as much as anyone, but sometimes the right tool really is a hammer. In that spirit, here is a Bourne shell script:&lt;br /&gt;&lt;pre&gt;#!/bin/sh&lt;br /&gt;#&lt;br /&gt;# pdfsplit - create a single-column version of a 2-column PDF file&lt;br /&gt;&lt;br /&gt;if [ $# -lt 1 ]&lt;br /&gt;then&lt;br /&gt;  echo "Usage: $0 file.pdf ..."&lt;br /&gt;  echo "  Produces file-split.pdf ..."&lt;br /&gt;  exit 1&lt;br /&gt;fi&lt;br /&gt;&lt;br /&gt;for input in "$@"&lt;br /&gt;do&lt;br /&gt;&lt;br /&gt;  base=`basename $input .pdf`&lt;br /&gt;  tmp=$base-split.tex&lt;br /&gt;  pages=`pdfinfo $input | grep Pages | awk '{print $2}'`&lt;br /&gt;&lt;br /&gt;  cat &amp;lt;&amp;lt;eof &gt;$tmp&lt;br /&gt;\\documentclass{article}&lt;br /&gt;\\usepackage[paperwidth=4.25in,paperheight=11in]{geometry}&lt;br /&gt;\\usepackage{pdfpages}&lt;br /&gt;\\begin{document}&lt;br /&gt;eof&lt;br /&gt;&lt;br /&gt;  n=1&lt;br /&gt;  while [ $n -le $pages ]&lt;br /&gt;  do&lt;br /&gt;&lt;br /&gt;    cat &amp;lt;&amp;lt;eof &gt;&gt;$tmp&lt;br /&gt;\\includepdf[pages=$n,noautoscale,offset=2.125in 0]{$input}&lt;br /&gt;\\includepdf[pages=$n,noautoscale,offset=-2.125in 0]{$input}&lt;br /&gt;eof&lt;br /&gt;&lt;br /&gt;    n=$((n+1))&lt;br /&gt;  done&lt;br /&gt;&lt;br /&gt;  cat &amp;lt;&amp;lt;eof &gt;&gt;$tmp&lt;br /&gt;\\end{document}&lt;br /&gt;eof&lt;br /&gt;&lt;br /&gt;  pdflatex $tmp&lt;br /&gt;&lt;br /&gt;  rm -f $tmp $base-split.aux $base-split.log&lt;br /&gt;&lt;br /&gt;done&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To use it, you will need pdflatex, the pdfpages package, and pdfinfo (from the poppler-utils package on my Ubuntu laptop).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-124514150322275073?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/124514150322275073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=124514150322275073' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/124514150322275073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/124514150322275073'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/06/shell-scripting-fun-pdfsplit.html' title='Shell scripting fun: pdfsplit'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-3617822914259159216</id><published>2011-06-04T22:41:00.002-05:00</published><updated>2011-11-10T16:54:49.688-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='notation'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>When Domain Specific Languages Attack!</title><content type='html'>&lt;b&gt;Or, why I don't particularly like Common Lisp&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Once upon a time, many years ago, Common Lisp was my favorite programming language. This was mostly when I was taking upper division classes at UT Austin, and mostly due to the AI faculty in the department, who were excellent teachers. In fact, I recall getting a laugh out of Ham Richards, when he read my answer to one of the questions on the final of the C++ class he was teaching: The question was on C++ operator precedence, and my answer included the comment, "I want my Lisp!"&lt;br /&gt;&lt;br /&gt;&lt;span style="float:right;margin:10px;"&gt;&lt;a href="http://www.amazon.com/gp/product/1593272812/ref=as_li_tf_il?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=1593272812"&gt;&lt;img border="0" src="http://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL160_&amp;ASIN=1593272812&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=wwwcrsrnet-20&amp;ServiceVersion=20070822" &gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=1593272812&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/span&gt;Anyway, enough about that. I have recently been meandering through &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/1593272812/ref=as_li_tf_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=1593272812"&gt;Land of Lisp: Learn to Program in Lisp, One Game at a Time!&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=1593272812&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, by Conrad Barski (check out the &lt;a href="http://nostarch.com/download/Lisp08.pdf"&gt;sample chapter&lt;/a&gt;, with the most violent programming example ever put into a textbook). (I've been meaning to learn something about Clojure, and I had nothing better to do.) The &lt;a href="http://landoflisp.com/"&gt;book&lt;/a&gt; gets a big thumbs up. It is entertaining, the cartoons (especially those that go with the evolution simulation) are perfect, the games bring back a surprising number of memories, &lt;em&gt;and&lt;/em&gt; I'm picking back up my Lisp. Fortunately or unfortunately, Barski uses Common Lisp, which is also bringing back some less pleasant memories.&lt;br /&gt;&lt;br /&gt;What happens when an embedded domain-specific language escapes into the general language in which it is embedded? The DSL probably doesn't fit in with the general language, stylistically, syntactically, or semantically, and the result may not be very pretty.&lt;br /&gt;&lt;br /&gt;One example that is less problematic involves parsing combinators; for one thing, parsers are usually isolated from the remainder of the program due to modularity concerns; for another, a parser isn't generally driving the remainder of the program.&lt;br /&gt;&lt;br /&gt;On the other hand, Common Lisp has three more problematic DSLs:&lt;ul&gt;&lt;li&gt;The setf accessor sublanguage,&lt;/li&gt;&lt;li&gt;the loop sublanguage, and&lt;/li&gt;&lt;li&gt;the format sublanguage.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The first of these is built for the generic settor, setf. The first argument to setf is a pattern, identifying a location in a data structure which is to be updated. This pattern can use the ever-present car and cdr, as well as things like structure field accessors. It does &lt;em&gt;not&lt;/em&gt; allow all general programs, and I &lt;em&gt;refuse&lt;/em&gt; to figure out what parts can be used, what cannot, and why.&lt;br /&gt;&lt;br /&gt;The second and the third are the reason for this post. Barski admits loop and format are not pretty in the two chapters dedicated to them, and shows a single-function game in the chapter dedicated to the latter. This game, robots, is a third-person, avoid-the-monsters thing, that I recall as being reasonably entertaining. Without much ado, here's the code:&lt;br /&gt;&lt;pre&gt;(defun robots ()&lt;br /&gt;  (loop named main with directions = '((q . -65) (w . -64) (e . -63) (a . -1)&lt;br /&gt;                                       (d . 1) (z . 63) (x . 64) (c . 65))&lt;br /&gt;     for pos = 544&lt;br /&gt;     then (progn (format t "~%qwe/asd/zxc to move, (t)eleport, (l)eave:")&lt;br /&gt;                 (force-output)&lt;br /&gt;                 (let* ((c (read))&lt;br /&gt;                        (d (assoc c directions)))&lt;br /&gt;                   (cond (d (+ pos (cdr d)))&lt;br /&gt;                         ((eq 't c) (random 1024))&lt;br /&gt;                         ((eq 'l c) (return-from main 'bye))&lt;br /&gt;                         (t pos))))&lt;br /&gt;     for monsters = (loop repeat 10 collect (random 1024))&lt;br /&gt;     then (loop for mpos in monsters collect (if (&gt; (count mpos monsters) 1)&lt;br /&gt;                                                 mpos&lt;br /&gt;                                                 (cdar (sort (loop for (k . d) in directions&lt;br /&gt;                                                                for new-mpos = (+ mpos d)&lt;br /&gt;                                                                collect (cons (+ (abs (- (mod new-mpos 64) (mod pos 64)))&lt;br /&gt;                                                                                 (abs (- (ash new-mpos -6) (ash pos -6))))&lt;br /&gt;                                                                              new-mpos))&lt;br /&gt;                                                             '&amp;lt;&lt;br /&gt;                                                             :key #'car))))&lt;br /&gt;     when (loop for mpos in monsters always (&gt; (count mpos monsters) 1))&lt;br /&gt;     return 'player-wins&lt;br /&gt;     do (format t "~%|~{~&amp;lt;|~%|~,65:;~A~&gt;~}|"&lt;br /&gt;                (loop for p below 1024 collect (cond ((member p monsters)&lt;br /&gt;                                                      (cond ((= p pos) (return-from main 'player-loses))&lt;br /&gt;                                                            ((&gt; (count p monsters) 1) #\#)&lt;br /&gt;                                                            (t #\A)))&lt;br /&gt;                                                     ((= p pos) #\@)&lt;br /&gt;                                                     (t #\space))))))&lt;br /&gt;&lt;/pre&gt;If you can figure out what is going on there, you're a better man than I. Even if you're not a man.&lt;br /&gt;&lt;br /&gt;My complaints: loop has absolutely nothing to do with the rest of CL, it has a very baroque interface, and enough features that I feel no urge to analyze or remember them all. format, on the other hand, is just simply loony.&lt;br /&gt;&lt;br /&gt;I spent some time unraveling robots, and came up with this, which is more understandable but which still contains the complexity of loop and format:&lt;br /&gt;&lt;pre&gt;(defparameter *directions* '((q . -65) (w . -64) (e . -63)&lt;br /&gt;                             (a . -1)            (d . 1)&lt;br /&gt;                             (z . 63)  (x . 64)  (c . 65)))&lt;br /&gt;&lt;br /&gt;(defparameter *initial-position* 544)&lt;br /&gt;&lt;br /&gt;(defparameter *n-monsters* 10)&lt;br /&gt;&lt;br /&gt;(defun initial-monsters () (loop repeat *n-monsters* collect (random 1024)))&lt;br /&gt;&lt;br /&gt;(defun read-move ()&lt;br /&gt;  (format t "~%qwe/asd/zxc to move, (t)eleport, (l)eave:")&lt;br /&gt;  (force-output)&lt;br /&gt;  (read))&lt;br /&gt;&lt;br /&gt;(defun monster-wrecked (mpos monsters) (&gt; (count mpos monsters) 1))&lt;br /&gt;&lt;br /&gt;(defun new-monster-position (pos mpos wrecked)&lt;br /&gt;  (labels ((player-distance (new-mpos) (+ (abs (- (mod new-mpos 64)&lt;br /&gt;                                                  (mod pos 64)))&lt;br /&gt;                                          (abs (- (ash new-mpos -6)&lt;br /&gt;                                                  (ash pos -6))))))&lt;br /&gt;    (let ((possible-moves (loop&lt;br /&gt;                for (k . d) in *directions*&lt;br /&gt;                for new-mpos = (+ mpos d)&lt;br /&gt;                collect (cons (player-distance new-mpos) new-mpos))))&lt;br /&gt;      (if (not wrecked) (cdar (sort possible-moves '&lt; :key #'car)) mpos))))&lt;br /&gt;&lt;br /&gt;(defun new-monster-positions (pos monsters)&lt;br /&gt;  (loop for mpos in monsters collect&lt;br /&gt;       (new-monster-position pos mpos (monster-wrecked mpos monsters))))&lt;br /&gt;&lt;br /&gt;(defun all-monsters-wrecked (monsters)&lt;br /&gt;  (every (lambda (mpos) (monster-wrecked mpos monsters)) monsters))&lt;br /&gt;&lt;br /&gt;(defun board-contents (pos monsters)&lt;br /&gt;  (loop for p below 1024 collect&lt;br /&gt;       (cond ((member p monsters) (if (monster-wrecked p monsters) #\# #\A))&lt;br /&gt;             ((= p pos) #\@)&lt;br /&gt;             (t #\space))))&lt;br /&gt;&lt;br /&gt;(defun robots ()&lt;br /&gt;  (loop named main&lt;br /&gt;     for pos = *initial-position* then&lt;br /&gt;       (let* ((c (read-move))&lt;br /&gt;              (d (assoc c *directions*)))&lt;br /&gt;         (cond (d (+ pos (cdr d)))&lt;br /&gt;               ((eq 't c) (random 1024))&lt;br /&gt;               ((eq 'l c) (return-from main 'bye))&lt;br /&gt;               (t pos)))&lt;br /&gt;     for monsters = (initial-monsters) then&lt;br /&gt;       (new-monster-positions pos monsters)&lt;br /&gt;     when (all-monsters-wrecked monsters) return 'player-wins&lt;br /&gt;     when (member pos monsters) return 'player-loses&lt;br /&gt;     do (format t "~%|~{~&lt;|~%|~,65:;~A~&gt;~}|" (board-contents pos monsters))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, bizarro DSLs are not limited to Common Lisp (&lt;a href="http://www.ccs.neu.edu/home/shivers/advisor-stmt-original.txt"&gt;Olin Shivers&lt;/a&gt;, who also wrote &lt;a href="http://www.scsh.net/"&gt;scsh&lt;/a&gt; and more importantly the &lt;a href="http://www.scsh.net/docu/html/man.html"&gt;acknowledgements&lt;/a&gt; in its manual, wrote a &lt;a href="http://www.ccs.neu.edu/home/shivers/citations.html#loop"&gt;paper&lt;/a&gt; about a &lt;a href="http://www.crsr.net/Programming_Languages/ReinventingImperative.html"&gt;suitably hideous&lt;/a&gt; version of loop in Scheme) but Common Lisp is the only example that I know about of several in one place, and of a culture that seems to really enjoy creating them.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Postscript&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;2000/07/24&lt;/em&gt; Per Bother infects Scheme with a &lt;a href="http://srfi.schemers.org/srfi-17/srfi-17.html"&gt;setf-alike&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-3617822914259159216?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/3617822914259159216/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=3617822914259159216' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3617822914259159216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/3617822914259159216'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/06/when-domain-specific-languages-attack.html' title='When Domain Specific Languages Attack!'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-581395021703289702</id><published>2011-06-03T11:41:00.000-05:00</published><updated>2011-06-03T11:41:06.189-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><title type='text'>Quote o' the Day: Software Awesomeness</title><content type='html'>Courtesy of reddit, Jesse Emery writes &lt;a href="http://www.jemery.com/2011/06/01/how-to-keep-your-software-awesome/"&gt;How to keep your software awesome&lt;/a&gt;, which has a stack of interesting ideas. A couple:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;It also means that your process should never, ever get in the way of someone wanting to make your software better. Do they have to ask permission or get approval to fix a bug? Really? Do they have to justify and sell their idea to you even if they’re willing to work on it in their own time? If the answer to any of these questions is “yes” then your process is working against, rather than for, your software. (Note: if you don’t trust your team at this level than either you shouldn’t have hired them or You Need to Let Go).&lt;/blockquote&gt;&lt;br /&gt;Regarding dealing with "technical debt", a piece of code that "is causing a lot of problems – either it’s causing bugs or making it hard to add (one of those that you thought long and hard about) features":&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;This type of work isn’t sexy for business owners or your sales force, but it still makes your product a lot better. Never lose sight of the fact that responsiveness and stability are every bit as much a part of your user experience as whether you used the glossy or the flat buttons.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-581395021703289702?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/581395021703289702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=581395021703289702' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/581395021703289702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/581395021703289702'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/06/quote-o-day-software-awesomeness.html' title='Quote o&apos; the Day: Software Awesomeness'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-9003265670267702905</id><published>2011-05-27T21:57:00.001-05:00</published><updated>2011-05-27T21:57:00.625-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><title type='text'>Diagonalization and the Continuum Hypothesis</title><content type='html'>I have recently been reading &lt;i&gt;Gödel's Theorem: An Incomplete Guide to its Use and Abuse&lt;/i&gt;, by Torkel Franzén, which is very good even though Franzén's attempts to explain &lt;a href="http://en.wikipedia.org/wiki/Kurt_G%C3%B6del"&gt;Gödel&lt;/a&gt;'s &lt;a href="http://en.wikipedia.org/wiki/G%C3%B6del%27s_incompleteness_theorems"&gt;theorems&lt;/a&gt; in natural language frequently feel like he is tap-dancing around the theorems themselves; when your explanation of a formal proof is more complex than the proof itself, something is wrong. On the other hand, his discussion the various philosophical (and other) conclusions that have been drawn from Gödel's theorems (and what is wrong with them) is very, very good.&lt;br /&gt;&lt;br /&gt;One thing that Franzén mentions that I had not known before is that &lt;a href="http://en.wikipedia.org/wiki/Georg_Cantor"&gt;Cantor&lt;/a&gt;'s &lt;a href="http://en.wikipedia.org/wiki/Continuum_hypothesis"&gt;Continuum Hypothesis&lt;/a&gt; is one of the most rare things in mathematics: a statement that is undecidable in &lt;a href="http://en.wikipedia.org/wiki/Zermelo-Fraenkel_set_theory"&gt;Zermelo-Fraenkel set theory&lt;/a&gt; (with the axiom of choice) &lt;b&gt;and&lt;/b&gt; one which is not specifically constructed to be undecidable in ZFC.&lt;br /&gt;&lt;br /&gt;Now, my purpose here is not really to talk about the Continuum Hypothesis (a.k.a. CH), nor about incompleteness, Gödel, or Franzén. Instead, I want to talk about some of the background to the CH and one of the top five mathematical proofs of the last, say, 200 years.&lt;br /&gt;&lt;br /&gt;To start with, say I have a set of three apples, a Red Delicious, a Fuji, and an Arkansas Black, and a set of three people: Alice, Bob, and Georg. How would I know whether or not the two sets are the same &lt;i&gt;size&lt;/i&gt;, or &lt;i&gt;cardinality&lt;/i&gt;? Simple. I need to put the two sets into a relationship where exactly one object from one set is associated with exactly one object from the other. If Alice eats the Red Delicious, Bob eats the Fuji, and Georg has the Arkansas Black flung at his head, then I know the two sets are the same size. What I have done is to put the two sets into a &lt;i&gt;one-to-one&lt;/i&gt; relation. (Technically, my one-to-one correspondence is a &lt;a href="http://en.wikipedia.org/wiki/Bijective_function"&gt;bijection&lt;/a&gt;; it needs to be both &lt;i&gt;injective&lt;/i&gt; and &lt;i&gt;surjective&lt;/i&gt;.)&lt;br /&gt;&lt;br /&gt;You might point out that I could just count the two sets to know if they were the same size. But that is ultimately the same thing: instead of putting a set of people in a one-to-one relation with a set of apples, I would be putting both sets of people and apples in a one-to-one relation with numbers. In fact, those are typically the counting numbers: 1, 2, 3, .... Counting the objects in a set simply amounts to putting the objects in a one-to-one relation with an initial-prefix subset of the counting numbers.&lt;br /&gt;&lt;br /&gt;At this point, I feel the need to toss out a couple of factoids that you may (or may not) already be aware of:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The counting numbers are infinite. That "..." indicates they continue forever.&lt;/li&gt;&lt;li&gt;There are (many) different kinds of numbers, including counting numbers, natural numbers (0, 1, 2, 3,...), integers (..., -2, -1, 0, 1, 2,...), rational numbers (x/y, where x and y are integers), and real numbers (0, 4, pi, e, 34.56,...).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;And here is a neat point that is the crux of this whole post: &lt;i&gt;by explicitly setting things in one-to-one relations, you can compare the sizes of infinite sets&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;But wait, you say, what the heck does &lt;i&gt;that&lt;/i&gt; mean? Here is a question for you: are there as many counting numbers as there are natural numbers. It does not seem like there should be, because the naturals have that extra 0 that is not included in the counting numbers. But infinite sets are weird. For one thing, I can't show you a one-to-one mapping, like I could with people and apples. Instead, I can exhibit a relation: \[ \forall n : n \in \textrm{natural} : (\exists c : c \in \textrm{counting} : n = c - 1) \] \[ \wedge \] \[ \forall c : c \in \textrm{counting} : (\exists n : n \in \textrm{natural} : n = c - 1) \] Or, in English, for any natural number \(n\) you can give me, I can give you back a counting number \(c\) such that \(n\) is \(c - 1\) and vice-versa. I'll spare you the demonstration that this relation is suitably one-to-one and just point out that it shows that the counting numbers and the naturals have the same cardinality, or size. Like I said, infinite sets are weird: one of the defining characteristics is that an infinite set can be put in a one-to-one correspondence with a proper subset of itself.&lt;br /&gt;&lt;br /&gt;So, if that is the case, how do the counting numbers and the naturals compare with the integers? It turns out that &lt;i&gt;they are the same size, too&lt;/i&gt;. Consider the following two functions, nat, which converts any integer to exactly one natural number, and int, which converts any natural number to an integer.&lt;br /&gt;\[ \textrm{nat}(n) = \begin{array}{cl} 2n &amp; \textrm{if } n \geq 0 \\ -2n - 1 &amp; \textrm{if } n &lt; 0 \end{array} \]\[ \textrm{int}(n) = \begin{array}{cl} n/2 &amp; \textrm{if } n \textrm{ even} \\ {-(n + 1) \over 2}  &amp; \textrm{if } n \textrm{ odd} \end{array} \]Without any particular argument that these two functions are inverses, I assert that they define a one-to-one relationship and therefore demonstrate that the natural numbers and the integers are the same cardinality.The rationals? This is where things start to get tricky. Consider for a moment the relationship I defined between the integers and the naturals above; what I did was to effectively take the integer number line, fold it in half between -1 and 0, and then alternately take one number from each half to match each natural number:&lt;table&gt;&lt;tr&gt;&lt;td&gt;0,&lt;/td&gt;&lt;td&gt;1,&lt;/td&gt;&lt;td&gt;2,&lt;/td&gt;&lt;td&gt;3,&lt;/td&gt;&lt;td&gt;4,&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;th&gt;(the naturals)&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0,&lt;/td&gt;&lt;td&gt;-1,&lt;/td&gt;&lt;td&gt;1,&lt;/td&gt;&lt;td&gt;-2,&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;th&gt;(the integers)&lt;/th&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;A similar trick can be done with the rationals by, first, only looking at the positive, natural numbers. (If I can put the positive fractions in a one-to-one relationship with natural numbers, I can use the same folding argument to include the negative fractions in the same sort of relationship.) Then, make a table with the numerators starting at 0 on the horizontal axis and the denominators starting at 1 on the vertical axis. (Obviously, the denominators cannot include zero.) Starting from the upper left cell, 0/1, zig-zag out one cell at a time, producing 1/1, 0/2, 2/1, 1/2, 0/3, collecting each upper-right-to-lower-left diagonal.&lt;table&gt;&lt;tr&gt;&lt;td&gt;0/1&lt;/td&gt;&lt;td&gt;1/1&lt;/td&gt;&lt;td&gt;2/1&lt;/td&gt;&lt;td&gt;3/1&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0/2&lt;/td&gt;&lt;td&gt;1/2&lt;/td&gt;&lt;td&gt;2/2&lt;/td&gt;&lt;td&gt;3/2&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0/3&lt;/td&gt;&lt;td&gt;1/3&lt;/td&gt;&lt;td&gt;2/3&lt;/td&gt;&lt;td&gt;3/3&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;Based on the table and the diagonal paths, I assert &lt;ol&gt;&lt;li&gt;Every positive rational number shows up at least once in this table, and by multiplying each entry by -1, I can construct another table where every negative rational number shows up, and so that every rational number appears in one of the two tables at least once.&lt;/li&gt;&lt;li&gt;By taking the diagonals in order, I can create a single list of the positive rationals, where each cell shows up in exactly one place in my list. By alternating between tables, I can construct a list containing every cell in both tables.&lt;/li&gt;&lt;li&gt;And therefore, &lt;em&gt;the set of rational numbers is not larger than the set of natural numbers.&lt;/em&gt;&lt;/ol&gt;Slick, eh?All I have done so far is to argue that a few different infinite sets are the same size, for my definition of "size", which is the ability to find a one-to-one relationship. If that's all I have, well, it's neat but not earthshaking. But now I get to one of my favorite proofs: Cantor's Diagonalization gag.Are the real numbers, say those between 0 and 1, the same size as the counting numbers? Say they are, which means I can construct a list of those real numbers, mapping each to the counting numbers:&lt;table&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0.435246687003...&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;0.076201826664...&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;0.000000000000...&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;0.999999999999...&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;...&lt;/td&gt;&lt;td&gt;...&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;It doesn't matter in the least what that order actually is, though, because I can now construct another real number between 0 and 1 that &lt;em&gt;cannot&lt;/em&gt; be on that list:&lt;ol&gt;&lt;li&gt;Take the first digit after the decimal point of the first number on the list.&lt;/li&gt;&lt;li&gt;Add one to this digit, wrapping around to 0 if the digit is 9.&lt;/li&gt;&lt;li&gt;Make this new digit the first digit after the decimal in my new number.&lt;/li&gt;&lt;li&gt;Repeat with the second digit after the decimal point of the second number, creating the second digit of my new number.&lt;/li&gt;&lt;li&gt;And so on, incrementing the next digit of the next number to get the corresponding digit of the new number.&lt;/li&gt;&lt;/ol&gt;This new number cannot be on the list created by the one-to-one relationship with the naturals, because the new number differs from every number on the list in at least one decimal place: 0.5810....As a result, &lt;em&gt;the cardinality of the real numbers between 0 and 1 is greater than the cardinality of the counting numbers, natural numbers, the integers, and the rationals.&lt;/em&gt; There are more real numbers between 0 and 1 than there are integers. &lt;b&gt;Infinity comes in multiple sizes.&lt;/b&gt;&lt;br /&gt;(Feel smarter yet? I know I do.)&lt;br /&gt;&lt;br /&gt;So, what's this continuum hypothesis, then? Cantor identified the size, or cardinality, of the integers as the transfinite number \(\aleph_0\). He went further to identify other transfinite numbers \(\aleph_1\), \(\aleph_2\), and so on, using completely different definitions. Now, we now know that the cardinality of the reals between 0 and 1, call it C, is greater than \(\aleph_0\), but the open question is whether C is less than or equal to \(\aleph_1\).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-9003265670267702905?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/9003265670267702905/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=9003265670267702905' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/9003265670267702905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/9003265670267702905'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/05/diagonalization-and-continuum.html' title='Diagonalization and the Continuum Hypothesis'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-1864392740767997863</id><published>2011-05-22T17:13:00.002-05:00</published><updated>2011-06-03T17:52:00.568-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='notation'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='random'/><title type='text'>De re profanae</title><content type='html'>According to Wikipedia, Alfréd Rényi, rather than Paul Erdős, said, "a mathematician is a device for turning coffee into theorems." My personal corollary to that is, "a programmer is a device for turning coffee into profanity." In the same vein, some other wit also said, "Profanity is the one language all programmers know best." There are many reasons why invective and informatics go hand-in-hand. I personally do not have a problem with that, though for most of my career I have been the one in the office who cursed the least. My sole reason was that when I do, I want people to pay attention. At the moment, however, I seem to be one of the fouler folks around. This is somewhat unsettling, but it makes for a quieter workplace anyway.&lt;br /&gt;&lt;br /&gt;I do not have a problem with profanity, but I do have a problem with euphemisms. Specifically, the term "f-bomb", which seems to be more common than I had realized. A while back, I ran across a story &lt;a href="http://chronicle.com/blogs/tweed/an-f-bomb-in-oral-communications/24088"&gt;in the Chronicle of Higher Education&lt;/a&gt; involving a student at &lt;a href="http://www.hindscc.edu/"&gt;Hinds Community College&lt;/a&gt; who received 4/5 of a suspension after uttering the word "fuck" after class. What I found upsetting was not the story (Who expects maturity from one of those diploma mills?), but the response. The title of the story was entertaining, but several of the commentors seemed to be using the term "f-bomb" with a straight face. Most of the Chronicle's readers are teachers and administrators at institutes of higher education; I expect them to know better.&lt;br /&gt;&lt;br /&gt;I am afraid I have news for some. "Fuck" is a word. It is not a bomb. It will not explode. It cannot kill anyone. If you, like those Chronicle readers, are dealing with people potentially in military service who are likely to face real explosive devices, it is a bit silly to dance around a &lt;em&gt;word&lt;/em&gt; as if it were dangerous.&lt;br /&gt;&lt;br /&gt;To bring this back to programming a bit, I am not a really big fan of profanity in code. Again, it does not bother me, but seeing a comment such as "This in fucking stupid!" is less useful to me than seeing a description why it is stupid and letting me exercise my own vocabulary. On the other hand, if you &lt;a href="http://meta.stackoverflow.com/questions/24079/is-the-language-brainfck-offensive/24206#24206"&gt;cannot mention "brainfuck" without turning red&lt;/a&gt;, I am going to have to suggest that you need to grow up a bit. (I hesitate to mention &lt;a href="http://maps.google.com/maps?q=scunthorpe"&gt;Scunthorpe, North Lincolnshire, England&lt;/a&gt;.) And if you interrupt me while I am battling Java, that will not be Yosemite Sam I am quoting.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;This post brought to you by the geniuses behind Java, who have shown their creativity by introducing every possible interface mistake, misdesign, and gratuitous stupidity known to mankind.&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-1864392740767997863?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/1864392740767997863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1864392740767997863' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1864392740767997863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1864392740767997863'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/05/de-re-profanae.html' title='De re profanae'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-6884156376880991631</id><published>2011-05-15T11:46:00.002-05:00</published><updated>2011-05-15T11:46:00.637-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><category scheme='http://www.blogger.com/atom/ns#' term='Dijkstra'/><title type='text'>Quote o' the Day: Tony Morris and Edsger W. Dijkstra on metaphor and analogy</title><content type='html'>While poking around Tony Morris' site, I found a fairly nice presentation on &lt;a href="http://projects.tmorris.net/public/what-does-monad-mean/artifacts/1.1/chunk-html/index.html"&gt;monads&lt;/a&gt;. In it, he makes a &lt;a href="http://projects.tmorris.net/public/what-does-monad-mean/artifacts/1.1/chunk-html/ar01s04s03.html"&gt;pithy quote&lt;/a&gt; which extends another pithy quote from &lt;a href="http://www.cs.utexas.edu/users/EWD/transcriptions/EWD12xx/EWD1205.html"&gt;Edsger Dijkstra&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;...but the most disorienting thing was that I found myself suddenly submerged in a verbal tradition that was totally foreign to me! [Legal professionals at a "Seminar on Information, Law and Technology"] were on the average very verbose —some even repetitive—, they had a tendency to "reason" by analogy and more than once I felt that speakers cared more about the potential influence of their words than about what they actually said. &lt;b&gt;-- EWD&lt;/b&gt;&lt;/blockquote&gt;&lt;blockquote&gt;Metaphors are training wheels that obscure learning opportunities and stall progress (object-oriented programming anyone?). &lt;b&gt;-- Tony Morris&lt;/b&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-6884156376880991631?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/6884156376880991631/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=6884156376880991631' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6884156376880991631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6884156376880991631'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/05/quote-o-day-tony-morris-and-edsger-w.html' title='Quote o&apos; the Day: Tony Morris and Edsger W. Dijkstra on metaphor and analogy'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-1230997409382655835</id><published>2011-05-09T23:01:00.031-05:00</published><updated>2011-05-09T23:01:00.152-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='toy problems'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='notation'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><category scheme='http://www.blogger.com/atom/ns#' term='data structure'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Tony Morris on static types</title><content type='html'>&lt;a href="http://blog.tmorris.net/understanding-practical-api-design-static-typing-and-functional-programming/"&gt;Tony's blog&lt;/a&gt; has an interesting discussion of API design and static typing that includes one of the best reasons for very strongly typed interfaces:&lt;br /&gt;&lt;blockquote&gt;Now, why these rules? Well, because if you can achieve the goal of enforcing these rules, then the next phone call that I get in L3 support from an upset client, I can be guaranteed that one of the following are true: &lt;ul&gt;&lt;li&gt;I have a bug in my code, in which case, the sooner the call, the better! …unless of course, fixing the bug results in only more bugs — but we have avoided that possibility — hopefully you can see why.&lt;/li&gt;&lt;li&gt;The client has misused the API and circumvented the type system. The client has used null, thrown an exception or performed a side-effect within the API or perhaps even used such things as Java reflection or even type-casting or type-casing. Unfortunately, in some environments, there’s not much I can do about enforcing that except impose a de facto rule where you assume non-existence of these possibilities (Just don’t do that!). Hopefully you haven’t yet jumped to the conclusion that any of these things are necessary or even useful — they aren’t.&lt;/li&gt;&lt;li&gt;The client is simply mistaken about the merits of their complaint.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;br /&gt;The only better reason I have heard of is the one I use: I would rather think hard for an hour or so to come up with an interface I would have a hard time screwing up than spend the next weeks or months trying to remember what is and what is not legitimate. In short, I'm lazy.&lt;br /&gt;&lt;br /&gt;What are the rules Morris is talking about? He has an advanced programming course assignment for &lt;br /&gt;&lt;blockquote&gt;students to write an API for the game tic-tac-toe. No need for the computer to tactically play tic-tac-toe — just an API that you can use to model the game itself. You can use any programming language you like, however, I think you will find certain environments to be lacking in the available tools, so I will guide you so that you’re not off somewhere “shaving yaks” so to speak.&lt;/blockquote&gt;The rules of the assignment are:&lt;br /&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;If you write a function, I must be able to call it with the same arguments and always get the same results, forever.&lt;/li&gt;&lt;li&gt;If I, as a client of your API, call one of your functions, I should always get a sensible result. Not null or an exception or other backdoors that cause the death of millions of kittens worldwide.&lt;/li&gt;&lt;li&gt;If I call move on a tic-tac-toe board, but the game has finished, I should get a compile-time type-error. In other words, calling move on inappropriate game states (i.e. move doesn’t make sense) is disallowed by the types.&lt;/li&gt;&lt;li&gt;If I call takeMoveBack on a tic-tac-toe board, but no moves have yet been made, I get a compile-time type-error.&lt;/li&gt;&lt;li&gt;If I call whoWonOrDraw on a tic-tac-toe board, but the game hasn’t yet finished, I get a compile-time type-error.&lt;/li&gt;&lt;li&gt;I should be able to call various functions on a game board that is in any state of play e.g. isPositionOccupied works for in-play and completed games.&lt;/li&gt;&lt;li&gt;It is not possible to play out of turn.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;br /&gt;The first rule is a typical virtue of functional programming: &lt;i&gt;referential transparency&lt;/i&gt;; a piece of code which violates that rule unnecessarily is much harder to understand than code that obeys it. The second rule is somewhat less typical, but still a well-known virtue: the function should be &lt;i&gt;total&lt;/i&gt;. A total function always returns a meaningful value, as opposed to a partial function which is not well-defined on some part of its domain; in other words, if the code calling it compiles without error, a total function always returns a useful value, while a partial function may throw an exception or return a bad value for some arguments.&lt;br /&gt;&lt;br /&gt;The third, fourth, fifth, and seventh rules are the interesting ones. (The sixth just says that there may be operations that the other rules &lt;i&gt;don't&lt;/i&gt; apply to.) These require encoding a model of the valid operations in the game into the types of the API.&lt;br /&gt;&lt;br /&gt;First, a little background. The &lt;i&gt;type&lt;/i&gt; of a computational artifact (a variable or function, for example) is actually a &lt;i&gt;predicate&lt;/i&gt; in a formal system defined by the type system of the programming language. (Go read up on the &lt;a href="http://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence"&gt;Curry-Howard correspondence&lt;/a&gt;, if you want. I'll still be here.) Some type systems are strong enough to make very strong, and very useful, statements about the program being written. In this case, Morris wants the API to specify limits on its interface to prevent invalid operations in the game of tic-tac-toe.&lt;br /&gt;&lt;br /&gt;Take the third rule: the move(board, position, player) operation should be invalid on a board that is in a finished-game state, for example. In other words, if you define "write" to be limited to code that compiles (and in particular, typechecks), then it should not be possible to write code that attempts to make a move on a finished board. Or, the move operation is governed by a predicate that prevents it from being applied to a finished board. Or, a board is governed by a predicate that prevents it from having a move applied to it.&lt;br /&gt;&lt;br /&gt;Now, writing the API and the predicates to satisfy these rules is not exactly easy. But it is possible in at least some programming languages. Specifically, Morris mentions Haskell, Scala, C# and &lt;i&gt;Java&lt;/i&gt;. (Morris' API for Java uses &lt;a href="http://functionaljava.org/"&gt;Functional Java&lt;/a&gt;, if you are interested.) There are a fair number of approaches to doing this in various languages, some of which can be euphemistically called "open research areas"; I would like to focus on a few of the less euphemistic.&lt;br /&gt;&lt;br /&gt;I found Morris' post from a link in &lt;a href="http://vasilrem.com/blog/software-development/tic-tac-toe-api-with-phantom-types/"&gt;Vasil Remeniuk's solution in Scala&lt;/a&gt; that uses &lt;a href="http://maniagnosis.crsr.net/2010/07/phantom-types-in-java-revisted.html"&gt;phantom types&lt;/a&gt;. I may come back in a bit to see how this looks in Java.&lt;br /&gt;&lt;br /&gt;If I am not completely confused, Morris' API uses higher-order functions to convince Java's type system to make the correct promises. Rather than have move(board, position, player) return a new board (to drastically oversimplify what I think Morris has done), move effectively takes three additional objects, each of which is a &lt;i&gt;functor&lt;/i&gt; (in C++ lingo) or "command object" (in Patternish), an object that encapsulates a function along with necessary data; that is, a half-assed implementation of a closure, or a first-class functional value. These three function-objects handle three possible cases: the move's position is already occupied, the game is already over, or the move is valid and the game should continue. This approach is uncommon in Java, and certainly looks hideous. But, it works.&lt;br /&gt;&lt;br /&gt;The third approach I want to mention actually involves weakening Morris' rules, in order to get an API that is somewhat less uncomfortable. Consider what happens if you make a valid move in tic-tac-toe: the resulting board may represent the end of the game, or it may allow the game to continue. Morris' API specifies that client code has to handle this bifurcation (Hi, Del!) by passing in two different function-objects for the two different cases, because Java's options are limited. (As I understand Morris, anyway.) The alternative I have in mind is to allow a certain minimal bit of non-total functionality, by having the move operation return &lt;i&gt;either&lt;/i&gt; an in-progress board or a final board, where the "either" is given by an Either algebraic type:&lt;br /&gt;&lt;pre&gt;public abstract class Either&amp;lt;S,T&gt; {&lt;br /&gt;  private static class Left&amp;lt;S,T&gt; extends Either&amp;lt;S,T&gt; {&lt;br /&gt;    private final S s;&lt;br /&gt;    private Left(S s) { this.s = s; }&lt;br /&gt;    @Override public S isLeft()  { return s; }&lt;br /&gt;    @Override public T isRight() { return null; }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private static class Right&amp;lt;S,T&gt; extends Either&amp;lt;S,T&gt; {&lt;br /&gt;    private final T t;&lt;br /&gt;    private Right(T t) { this.t = t; }&lt;br /&gt;    @Override public S isLeft()  { return null; }&lt;br /&gt;    @Override public T isRight() { return t; }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public abstract S isLeft();&lt;br /&gt;  public abstract T isRight();&lt;br /&gt;&lt;br /&gt;  public static &amp;lt;S,T&gt; Either&amp;lt;S,T&gt; left(S s)  { return new Left&amp;lt;S,T&gt;(s); }&lt;br /&gt;  public static &amp;lt;S,T&gt; Either&amp;lt;S,T&gt; right(T t) { return new Right&amp;lt;S,T&gt;(t); }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This class is used something like:&lt;pre&gt;&lt;!-- --&gt;&lt;br /&gt;    Either&amp;lt;Integer,String&gt; is1 = Either.left(4);&lt;br /&gt;    Either&amp;lt;Integer,String&gt; is2 = Either.right("four");&lt;br /&gt;    &lt;br /&gt;    System.out.println(is1.isLeft() + " " + is1.isRight());&lt;br /&gt;    System.out.println(is2.isLeft() + " " + is2.isRight());&lt;br /&gt;&lt;/integer,string&gt;&lt;/integer,string&gt;&lt;/pre&gt;where the output is:&lt;pre&gt;&lt;!-- --&gt;&lt;br /&gt;4 null&lt;br /&gt;null four&lt;br /&gt;&lt;/pre&gt;Notice that Either encodes a type-level choice; a value of Either contains a value of one of two other types. In the tic-tac-toe case, move can return Either&amp;lt;InProgressBoard,FinishedBoard&gt; and the client code can pick out the right board, at which point it can type-safely take the next step. The non-totality enters because calling isRight on a Left value returns null; client code using that value cannot do anything unsound, but it also will not get a compile-time error. This approach provides an API that more closely resembles normal Java but weakens Morris' rule three to something like "If I call move on a tic-tac-toe board, but the game has finished, I should get a compile-time type-error unless I have done something god-awful stupid. In other words, I am required to check the result and actively be idiotic to get a run-time error." Which is bad, don't get me wrong, but may not be as bad as trying to explain Functional Java to the numbskulls soiling your API by trying to use it.&lt;br /&gt;&lt;br /&gt;Morris would disagree, as witnessed by his comments quoted above and by the following, from &lt;a href="http://blog.tmorris.net/a-brief-point-on-static-typing/"&gt;another post&lt;/a&gt;:&lt;blockquote&gt;Some people like to think “correctness” includes the thoughts of one or more persons in order to make the assessment. For example, one might proclaim, “sure you have a proof of program termination, but that is not the program that I asked for!” I think this is a poor use of the term “correctness” and I am not considering it any further here.&lt;/blockquote&gt;As a bit of a formalist myself, I can certainly feel the attraction to that definition of correctness, but it still leaves one in the unpleasant position of having a rather strange, technical meaning for a commonly-used word; somewhat like the difference between &lt;em&gt;true&lt;/em&gt; and &lt;em&gt;formally proven&lt;/em&gt;. For myself, I have seen too many comments to the effect of "if we proved everything correct, there wouldn't be any bugs" (for example, see David Harel's &lt;em&gt;Algorithmics&lt;/em&gt;) or "[system X] has [huge percentage Y] devoted to handling situations that shouldn't occur" (see David Gries' &lt;em&gt;The Science of Programming&lt;/em&gt;); even with software that is correct according to Morris, my to-do list would likely not be much shorter and TCP would &lt;em&gt;still&lt;/em&gt; have to send retransmissions.&lt;br /&gt;&lt;br /&gt;In any case, Morris has given a really nice challenge as well as an excellent description of why the challenge is worthwhile, and I too look forward to the day when I can be assured that that phone call likely represents genuine bug.&lt;br /&gt;&lt;br /&gt;[Edit] Amazingly, a quick-and-dirty translation of Remeniuk's Scala code to Java seems to demonstrate the properties I was looking for. (This code was put together very quickly and does not attempt to satisfy all of Morris' rules. Nor does it meet all of the guarantees made by Remeniuk's code. But it's not bad.)&lt;br /&gt;&lt;pre&gt;public class Phantom&lt;br /&gt;{&lt;br /&gt;  static abstract class Mark { }&lt;br /&gt;  static class Nought extends Mark { }&lt;br /&gt;  static class Cross extends Mark { }&lt;br /&gt;  &lt;br /&gt;  /* ... */&lt;br /&gt;    &lt;br /&gt;  static abstract class GameState { }&lt;br /&gt;&lt;br /&gt;  static class NotFinished extends GameState { }&lt;br /&gt;  static class Started extends NotFinished { }&lt;br /&gt;  static class NotStarted extends NotFinished { }&lt;br /&gt;  &lt;br /&gt;  static class Finished extends GameState { }&lt;br /&gt;  static class Failed extends Finished { }&lt;br /&gt;  static class WinState extends Finished { }&lt;br /&gt;  static class DrawState extends Finished { }&lt;br /&gt;&lt;br /&gt;  static class Position {&lt;br /&gt;    public final int x, y;&lt;br /&gt;    Position(int x, int y) { this.x = x; this.y = y; }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  static final class NextTurn&amp;lt;Last extends Mark,Next extends Mark&gt; {&lt;br /&gt;    // Type witnesses: values used only to force specific types.&lt;br /&gt;    public final NextTurn&amp;lt;Nought,Cross&gt; crossesTurn = new NextTurn&amp;lt;Nought, Cross&gt;();&lt;br /&gt;    public final NextTurn&amp;lt;Cross,Nought&gt; noughtsTurn = new NextTurn&amp;lt;Cross, Nought&gt;();&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  // S: Board's position in the game: NotStarted, Started, etc.&lt;br /&gt;  // M: Last mark to be played.&lt;br /&gt;  // Next: Next mark to be played.&lt;br /&gt;  static class Board&amp;lt;S extends GameState, M extends Mark&gt; {&lt;br /&gt;    &amp;lt;Next extends Mark, S extends Started&gt;&lt;br /&gt;      Either&amp;lt;Board&amp;lt;Finished,Next&gt;,Board&amp;lt;Started,Next&gt;&gt;&lt;br /&gt;      move(Position position, NextTurn&amp;lt;M,Next&gt; nextTurn, S isNotFinished) { /*...*/ }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;One thing that differs from the Scala code is that I have had to use explicit type witness values; in Scala I believe they are implicit. Also, the Scala code uses the same function argument approach as Morris', by calling Either.fmap.&lt;br /&gt;&lt;br /&gt;This code would be very easy to circumvent, but it does demonstrate some of the desired features:&lt;br /&gt;&lt;pre&gt;  public static void main(String[] args) {&lt;br /&gt;    new Board&amp;lt;NotStarted,Nought&gt;()&lt;br /&gt;    .move(new Position(1,1), NextTurn.crossesTurn, new Started())&lt;br /&gt;    .isRight() // The resulting board will not be Finished.&lt;br /&gt;    .move(new Position(1,2), NextTurn.crossesTurn, new Started());&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;The second move() call indicates that Cross is taking another turn, and fails to compile with the following error:&lt;br /&gt;&lt;pre&gt;$ javac -cp src src/tictactoe/Phantom.java&lt;br /&gt;src/tictactoe/Phantom.java:87:&lt;br /&gt; &amp;lt;Next,S&gt;move(tictactoe.Phantom.Position,&lt;br /&gt;              tictactoe.Phantom.NextTurn&amp;lt;tictactoe.Phantom.Cross,Next&gt;,&lt;br /&gt;              S) in &lt;br /&gt;    tictactoe.Phantom.Board&amp;lt;tictactoe.Phantom.Started,tictactoe.Phantom.Cross&gt;&lt;br /&gt;  cannot be applied to&lt;br /&gt;    (tictactoe.Phantom.Position,&lt;br /&gt;     tictactoe.Phantom.NextTurn&amp;lt;tictactoe.Phantom.Nought,tictactoe.Phantom.Cross&gt;,&lt;br /&gt;     tictactoe.Phantom.Started)&lt;br /&gt;      .isRight().move(new Position(1,2), new NextTurn&amp;lt;Nought, Cross&gt;(), new Started());&lt;br /&gt;                ^&lt;br /&gt;  1 error&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/5087326709910512917-1230997409382655835?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/1230997409382655835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1230997409382655835' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1230997409382655835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1230997409382655835'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/05/tony-morris-on-static-types.html' title='Tony Morris on static types'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-7187140234562052525</id><published>2011-05-02T22:19:00.000-05:00</published><updated>2011-05-02T22:19:38.277-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='unix'/><title type='text'>There are limits to what you can do in the child process.</title><content type='html'>According to the Mac OS X manual page for &lt;a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man2/fork.2.html"&gt;fork(2)&lt;/a&gt;,&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;CAVEATS&lt;/b&gt;&lt;br /&gt;There are limits to what you can do in the child process.  To be totally safe you should restrict yourself to only executing async-signal safe operations until such time as one of the exec functions is called.  All APIs, including global data symbols, in any framework or library should be assumed to be unsafe after a fork() unless explicitly documented to be safe or async-signal safe.  If you need to use these frameworks in the child process, you must exec.  In this situation it is reasonable to exec yourself.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Async-signal safe operations are (according to Mac OS X sigaction(2)):&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;Base Interfaces:&lt;/b&gt; _exit(), access(), alarm(), cfgetispeed(), cfgetospeed(), cfsetispeed(), cfsetospeed(), chdir(), chmod(), chown(), close(), creat(), dup(), dup2(), execle(), execve(), fcntl(), fork(), fpathconf(), fstat(), fsync(), getegid(), geteuid(), getgid(), getgroups(), getpgrp(), getpid(), getppid(), getuid(), kill(), link(), lseek(), mkdir(), mkfifo(), open(), pathconf(), pause(), pipe(), raise(), read(), rename(), rmdir(), setgid(), setpgid(), setsid(), setuid(), sigaction(), sigaddset(), sigdelset(), sigemptyset(), sigfillset(), sigismember(), signal(), sigpending(), sigprocmask(), sigsuspend(), sleep(), stat(), sysconf(), tcdrain(), tcflow(), tcflush(), tcgetattr(), tcgetpgrp(), tcsendbreak(), tcsetattr(), tcsetpgrp(), time(), times(), umask(), uname(), unlink(), utime(), wait(), waitpid(), write().&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Realtime Interfaces:&lt;/b&gt; aio_error(), clock_gettime(), sigpause(), timer_getoverrun(), aio_return(), fdatasync(), sigqueue(), timer_gettime(), aio_suspend(), sem_post(), sigset(), timer_settime().&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ANSI C Interfaces:&lt;/b&gt; strcpy(), strcat(), strncpy(), strncat(), and perhaps some others.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Extension Interfaces:&lt;/b&gt; strlcpy(), strlcat().&lt;br /&gt;&lt;br /&gt;All functions not in the above lists are considered to be unsafe with respect to signals. That is to say, the behaviour of such functions when called from a signal handler is undefined. In general though, signal handlers should do little more than set a flag; most other actions are not safe.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;The bottom line is that the child process is apparently sharing a lot with the parent process, along the same lines as older BSD's &lt;a href="http://www.unixguide.net/unix/programming/1.1.2.shtml"&gt;vfork(2)&lt;/a&gt; optimization. The normal Unix behavior of fork(2) involves sharing almost nothing; with the exception of some pretty painful operations, the child process shares nothing with the parent. Resources are duplicated instead.&lt;br /&gt;&lt;br /&gt;fork(2) is a fundamental operation in Unix; radical changes in it's behavior imply radical changes in the operating system. Certainly, reading that CAVEATS paragraph would lead me to believe that essentially no existing Unix programs could run on iOS without significant code changes. (Ahhh, brings back memories of the bad old days when I had to deal with SunOS, Solaris, AIX, HP-UX, and Irix; all of which claimed to be Unix, but all of which had their own bizarre behavior from basic operations. Wonderful.)&lt;br /&gt;&lt;br /&gt;My conclusion: Mac OS X isn't Unix, no matter how many people say it is. That man page is a fine counter-example.&lt;br /&gt;&lt;br /&gt;Want to know more about Unix system programming? See &lt;em&gt;&lt;a href="http://www.amazon.com/Programming-Environment-Addison-Wesley-Professional-Computing/dp/0201563177/ref=ntt_at_ep_dpt_3"&gt;Advanced Programming in the Unix Environment&lt;/a&gt;&lt;/em&gt; by the late W. Richard Stevens. (Truthfully, you'll probably want the &lt;a href="http://www.amazon.com/Advanced-Programming-UNIX-Environment-2nd/dp/0201433079/ref=dp_ob_title_bk"&gt;second edition&lt;/a&gt;.) It shouldn't take long to appreciate the depraved insanity that is the Unix family tree.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-7187140234562052525?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/7187140234562052525/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=7187140234562052525' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7187140234562052525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7187140234562052525'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/05/there-are-limits-to-what-you-can-do-in.html' title='There are limits to what you can do in the child process.'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-5414394377817286940</id><published>2011-04-13T21:43:00.001-05:00</published><updated>2011-04-14T17:25:25.428-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='data structure'/><title type='text'>SQL Combinators in Java</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Combinatory_logic"&gt;Combinators&lt;/a&gt; are another technique common in functional programming which seems to be significantly less common in object-oriented languages. This is unfortunate, because combinators work very well in an object-oriented design. What I am going to present below is a very simple use of them that hopefully displays some of their features. Other common examples include &lt;a href="http://en.wikipedia.org/wiki/Parser_combinator"&gt;parsers&lt;/a&gt; and various embedded domain specific languages.&lt;br /&gt;&lt;br /&gt;Now, I will admit that I am a crazed neo-Luddite. I am proud to say that I hate persistent objects, believe remote procedure calls are evil, and regard most of the enterprise development infrastructure and practices with a considerable amount of disdain. But the bottom line is that I do not use Hibernate, JPA, or any of the other object/relational/database/mapper hoo-has. They, in the immortal words of Del, purport to make something easier that was not difficult in the first place. In doing so, they stack another layer of &lt;em&gt;stuff&lt;/em&gt; on top of the actual solution; witness the fun when combining &lt;a href="http://www.osgi.org/blog/2007/06/osgi-and-hibernate.html"&gt;OSGi modularity with Hibernate&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Instead, I am perfectly happy writing SQL statements in my cheerfully modular code, performing just the operations that I need when I need them, and enjoying the control that I get. However, there are times when that is not enough, when plain SQL statements will not do the job. One such case that has come up several times in my career is a semi-general, ad hoc query based on a HTTP request.&lt;br /&gt;&lt;br /&gt;For example, consider a web form that displays rows from a database table. This web form submits a number of parameters, and based on those parameters the server-side code formulates a query that returns the appropriate rows, which are then returned to the client. Now, there are two ways to formulate a SQL query: parameterized and non-parameterized. The latter involves building a text string including the SQL and the values to be selected; the values must be appropriately sanitized to avoid SQL injection. I prefer the parameterized option. The thing about the parameterized option is that it needs two passes: one to build the SQL, "SELECT * FROM table WHERE whosit = ?" and one to inject "Fred" to match ? number 1 (remembering the order that the ?'s came in, too). This is where the combinators enter the picture. These combinators provide a way of building the where-clause of a SQL statement in a semi-general way.&lt;br /&gt;&lt;br /&gt;To demonstrate, this code selects all of the rows with NAMEs equal to "Doe".&lt;br /&gt;&lt;pre&gt;Predicate p = Predicate.stringEquals("NAME", "Doe");&lt;br /&gt;statement = connection.prepareStatement("SELECT * FROM people WHERE " + p.toSql());&lt;br /&gt;p.parameterize(statement);&lt;br /&gt;ResultSet rs = statement.executeQuery();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The following example selects all of the rows with NAMEs equal to "Doe" and ADDRESSes LIKE "Main Street".&lt;br /&gt;&lt;pre&gt;Predicate p = Predicate.and();&lt;br /&gt;p.add(Predicate.stringEquals("NAME", "Doe"));&lt;br /&gt;p.add(Predicate.stringLike("ADDRESS", "Main Street"));&lt;br /&gt;statement = connection.prepareStatement("SELECT * FROM people WHERE " + p.toSql());&lt;br /&gt;p.parameterize(statement);&lt;br /&gt;ResultSet rs = statement.executeQuery();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finally, this code selects all of the rows with NAMES equal to "Doe" and orders the result by "CITY", ascending.&lt;br /&gt;&lt;pre&gt;Predicate p = Predicate.orderedByAscending(Predicate.stringEquals("NAME", "Doe"), "CITY");&lt;br /&gt;statement = connection.prepareStatement("SELECT * FROM people WHERE " + p.toSql());&lt;br /&gt;p.parameterize(statement);&lt;br /&gt;ResultSet rs = statement.executeQuery();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The primary abstract interface to a combinator is to evaluate it. (This is one of the reasons they work so well in functional languages.) For my SQL combinator, I wanted a little richer interface:&lt;br /&gt;&lt;pre&gt;public abstract class Predicate&lt;br /&gt;{&lt;br /&gt;  /**&lt;br /&gt;   * Return the SQL for the given predicate, including parameter markers (?).&lt;br /&gt;   * @return A String.&lt;br /&gt;   */&lt;br /&gt;  public abstract String toSql();&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * Set the parameters in the {@link PreparedStatement} associated with the parameter markers from the toSQL string.&lt;br /&gt;   * This method must be called after the statement is created from the string and before the query is executed.&lt;br /&gt;   * @param statement {@link PreparedStatement} which should have the values injected into it.&lt;br /&gt;   * @throws SQLException If the parameterization fails.&lt;br /&gt;   */&lt;br /&gt;  public void parameterize(PreparedStatement statement) throws SQLException&lt;br /&gt;  {&lt;br /&gt;    [...]&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Test whether the {@link Predicate} represents an empty WHERE clause.&lt;br /&gt;   * &lt;br /&gt;   * @return True if the predicate represents an empty WHERE clause, false otherwise.&lt;br /&gt;   */&lt;br /&gt;  public boolean isEmpty() { return false; }&lt;br /&gt;&lt;br /&gt;[...]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The two key methods are toSql(), which returns the SQL predicate clause, and parameterize(), which accepts a PreparedStatement generated from the SQL and inserts the values. A base-case combinator (ignoring the empty one) is something that compares a value with a column:&lt;br /&gt;&lt;pre&gt;  public static class StringEquals extends Predicate&lt;br /&gt;  {&lt;br /&gt;    private final String column;&lt;br /&gt;    private final String value;&lt;br /&gt;    &lt;br /&gt;    public StringEquals(String column, String value)&lt;br /&gt;    {&lt;br /&gt;      this.column = column;&lt;br /&gt;      this.value = value;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String toSql()&lt;br /&gt;    {&lt;br /&gt;      return String.format("(%s = ?)", column, operator);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    protected int setParameter(int index, PreparedStatement statement) throws SQLException&lt;br /&gt;    {&lt;br /&gt;      statement.setString(index, value);&lt;br /&gt;      return index + 1;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The parameterize() method of the Predicate calls setParameter() for the Predicate structure; each setParameter returns the &lt;em&gt;next&lt;/em&gt; index value into the SQL statement.&lt;br /&gt;&lt;pre&gt;  [...]&lt;br /&gt;  public void parameterize(PreparedStatement statement) throws SQLException&lt;br /&gt;  {&lt;br /&gt;    this.setParameter(1, statement);&lt;br /&gt;  }&lt;br /&gt;  [...]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;By ensuring that the order of the ?'s in the SQL is the same as the order that setParameter() is called, the values are associated with the appropriate clauses.&lt;br /&gt;&lt;br /&gt;Another combinator class is used to search for timestamps appearing on a given day:&lt;br /&gt;&lt;pre&gt;  public static class OnDate extends ColumnComparison&lt;br /&gt;  {&lt;br /&gt;    private final String column;&lt;br /&gt;    private final Date date;&lt;br /&gt;    &lt;br /&gt;    protected OnDate(String column, Date date)&lt;br /&gt;    {&lt;br /&gt;      this.column = column;&lt;br /&gt;      this.date = date;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String toSql()&lt;br /&gt;    {&lt;br /&gt;      return String.format("(%s BETWEEN ? AND ?)", column);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    protected int setParameter(int index, PreparedStatement statement) throws SQLException&lt;br /&gt;    {&lt;br /&gt;      final Calendar calendar = Calendar.getInstance();&lt;br /&gt;      calendar.setTime(date);&lt;br /&gt;      statement.setDate(index, new Date(calendar.getTimeInMillis()));&lt;br /&gt;      calendar.roll(Calendar.DATE, true);&lt;br /&gt;      statement.setDate(index + 1, new Date(calendar.getTimeInMillis()));&lt;br /&gt;      return index + 2;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The interesting part of combinators (and the ad hoc query) is the ability to generate a higher-level Predicate from one or more more-basic predicates. In this case, that is the purpose of And and Or:&lt;br /&gt;&lt;pre&gt;  private static class And extends Aggregate { public And() { super(" AND "); } }&lt;br /&gt;  private static class Or  extends Aggregate { public Or() { super(" OR "); } }&lt;br /&gt;&lt;/pre&gt;which are based on a general Aggregate:&lt;br /&gt;&lt;pre&gt;  public abstract static class Aggregate extends Predicate implements Collection&lt;Predicate&gt;&lt;br /&gt;  {&lt;br /&gt;    protected final String join;&lt;br /&gt;    protected final List&lt;Predicate&gt; subPredicates = new ArrayList&lt;Predicate&gt;();&lt;br /&gt;    &lt;br /&gt;    protected Aggregate(String join)&lt;br /&gt;    {&lt;br /&gt;      this.join = join;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    public String toSql()&lt;br /&gt;    {&lt;br /&gt;      List&lt;String&gt; sqls = new ArrayList&lt;String&gt;(subPredicates.size());&lt;br /&gt;      // Some hot mapping action here.&lt;br /&gt;      for (Predicate sub : subPredicates)&lt;br /&gt;      {&lt;br /&gt;        sqls.add(sub.toSql());&lt;br /&gt;      }&lt;br /&gt;      return StringUtils.join(sqls, join);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    protected int setParameter(int index, PreparedStatement statement) throws SQLException&lt;br /&gt;    {&lt;br /&gt;      for (Predicate sub : subPredicates)&lt;br /&gt;      {&lt;br /&gt;        index = sub.setParameter(index, statement);&lt;br /&gt;      }&lt;br /&gt;      return index;&lt;br /&gt;    }&lt;br /&gt;  [...]&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The final piece is the capability of ordering the results of the query.&lt;br /&gt;&lt;pre&gt;  public static class Ordered extends Predicate&lt;br /&gt;  {&lt;br /&gt;    private final String sortColumn;&lt;br /&gt;    private final Predicate predicate;&lt;br /&gt;    private final boolean ascending;&lt;br /&gt;    &lt;br /&gt;    protected Ordered(Predicate predicate, boolean ascending, String column)&lt;br /&gt;    {&lt;br /&gt;      this.predicate = predicate;&lt;br /&gt;      this.sortColumn = column;&lt;br /&gt;      this.ascending = ascending;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    protected int setParameter(int index, PreparedStatement statement) throws SQLException&lt;br /&gt;    {&lt;br /&gt;      return predicate.setParameter(index, statement);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String toSql()&lt;br /&gt;    {&lt;br /&gt;      // Default: ASC&lt;br /&gt;      final String asc = ascending ? "" : " DESC";&lt;br /&gt;      return predicate.toSql() + " ORDER BY " + sortColumn + asc;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;There is a small problem here; once an Ordered has been wrapped around a Predicate, the result is no longer really a Predicate; it admits the same interface, but an Ordered instance cannot legitimately be added to an And or Or collection. I will leave the fix as an exercise for the reader.&lt;br /&gt;&lt;br /&gt;To make using Predicates easier, I included a number of static methods that can be used to create individual instances.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;and() returns an And aggregate which will join its sub-predicates with AND.&lt;/li&gt;&lt;li&gt;or() returns an Or aggregate which will join its sub-predicates with OR.&lt;/li&gt;&lt;li&gt;stringEquals(String, String) returns a simple StringEquals predicate joining a column with a String via '='; this comparison is case sensitive.&lt;/li&gt;&lt;li&gt;stringEqualsIgnoreCase(String, String) returns a simple predicate joining a column with a String via '='; this comparison is case-insensitive.&lt;/li&gt;&lt;li&gt;stringLike(String, String) returns a simple predicate joining a column with a SQL pattern expression via 'LIKE'; this comparison is case-insensitive.&lt;/li&gt;&lt;li&gt;onDate(String, Date) returns a simple predicate joining a column with a Date; BETWEEN is used to allow any time between DATE and the next day.&lt;/li&gt;&lt;li&gt;orderedBy(Predicate, boolean, String) returns an Ordered predicate, ordered as described by the flag and the column names.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The examples I gave are not as syntactically nice as some of the DSLs implementable in Haskell, say. (But in Java, what is?) However, it does allow me to cleanly build up a predicate in stages&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5414394377817286940?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/5414394377817286940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5414394377817286940' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5414394377817286940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5414394377817286940'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/04/sql-combinators-in-java.html' title='SQL Combinators in Java'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-8756271379426229133</id><published>2011-04-01T22:56:00.002-05:00</published><updated>2011-11-10T16:45:15.170-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Poison, forensic medicine, and facts</title><content type='html'>&lt;span style="float:right;margin:10px"&gt;&lt;a href="http://www.amazon.com/gp/product/B004Z8LM3M/ref=as_li_tf_il?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=B004Z8LM3M"&gt;&lt;img border="0" src="http://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL160_&amp;ASIN=B004Z8LM3M&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=wwwcrsrnet-20&amp;ServiceVersion=20070822" &gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=B004Z8LM3M&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/span&gt;I like &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/B004Z8LM3M/ref=as_li_tf_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=B004Z8LM3M"&gt;The Poisoner's Handbook: Murder and the Birth of Forensic Medicine in Jazz Age New York&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=B004Z8LM3M&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;. Really, I do.Deborah Blum writes well, the story is fascinating, the history is both vital as well as, well, timely. But it could have been so much better.&lt;br /&gt;&lt;br /&gt;I don't really mind Blum's bizarre dual organization: the book's chapters are named after, and focus on, specific poisons like chloroform, wood alcohol, cyanides, and so on, but the text is also chronological, from 1915 in chapter one, 1918 and 1919 for chapter two, 1920 through 1922 for chapter three, and so on. I mean, it follows the career of New York's first medical examiner and his forensic chemist, Alexander Gettler. Through a career, it's obvious that some issues, like some poisons, will be more important at specific times. Likewise, some poisons, like some issues, will continue to rear their heads through the years although perhaps in different guises.&lt;br /&gt;&lt;br /&gt;[My coroner story: I am from Texas. My required undergraduate Texas government class was enlivened by stories like the Justice of the Peace who, acting as coroner, declared a death involving something like 27 bullet wounds to be a suicide.]&lt;br /&gt;&lt;br /&gt;I also don't really mind when Blum's writing style ventures far beyond the pale; comparing the color of a body poisoned by carbon monoxide with the hourglass on a black widow may impress some of the reviewers I have read, but it is just too much of a stretch for me.&lt;br /&gt;&lt;br /&gt;What I do mind is a lack of trust. History is vital because, to paraphrase Marx and Santayana, those who cannot remember the past are condemned to be characters in a bad comedy. Blum's tale has many lessons, from prohibition to overconfidence. (Did anyone notice the similarities between Marie Curie and Thomas Midgley, Jr., the GM engineer who introduced tetraethyl lead to gasoline, washed his hands in the stuff for the press, and who was last seen vacationing in Europe and seeking treatment for lead poisoning?)&lt;br /&gt;&lt;br /&gt;But details matter. This story is about science; wrong is wrong. When Blum explains that "gamma radiation [...] contains a dangerous mixture of X-rays and other subatomic materials" (pg. 184), or that "beverages containing ethyl alcohol were known as 'hard liquor'" (pg. 197), I am left wondering if her other assertions, such as "one of the benefits, or curses, of [...] Prohibition: every drink was a stiff one" (pg. 200) are similarly fuzzy. One might imagine that a &lt;a href="http://blogs.plos.org/speakeasyscience/"&gt;PLoS blogger&lt;/a&gt;&amp;nbsp;would know the importance of checking facts.&lt;br /&gt;&lt;br /&gt;So I am left with one conclusion: although &lt;i&gt;The Poisoner's Handbook&lt;/i&gt; is a good read, it is a failure as anything more.&lt;br /&gt;&lt;br /&gt;[Ps. More about Midgley. According to &lt;a href="http://en.wikipedia.org/wiki/Thomas_Midgley,_Jr.#Synthesis_of_Freon"&gt;Wikipedia&lt;/a&gt;, he was also involved in the synthesis of chlorofluorocarbon&amp;nbsp;refrigerants, the production of &lt;a href="http://en.wikipedia.org/wiki/Chlorofluorocarbon"&gt;"[...] which&amp;nbsp;is being phased out by the Montreal Protocol because they contribute to ozone depletion"&lt;/a&gt;. Also, he died of strangulation after becoming entangled in a "&lt;a href="http://www.time.com/time/magazine/article/0,9171,801605,00.html"&gt;a self-devised harness for getting in &amp;amp; out of bed&lt;/a&gt;" after being disabled by polio.]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-8756271379426229133?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/8756271379426229133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=8756271379426229133' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/8756271379426229133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/8756271379426229133'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/04/poison-forensic-medicine-and-facts.html' title='Poison, forensic medicine, and facts'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-8062106839431377579</id><published>2011-04-01T12:55:00.001-05:00</published><updated>2011-05-10T12:01:48.722-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='link'/><title type='text'>Link o' the day: Johann Carl Friedrich Gauss</title><content type='html'>A little known fact about Gauss: &lt;a href="http://www.gaussfacts.com/view/Mathematics/9"&gt;&lt;blockquote&gt;It only takes Gauss 4 minutes to sing “Aleph-Null Bottles of Beer on the Wall”. &lt;/blockquote&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-8062106839431377579?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/8062106839431377579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=8062106839431377579' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/8062106839431377579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/8062106839431377579'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/04/link-o-day-johann-carl-friedrich-gauss.html' title='Link o&apos; the day: Johann Carl Friedrich Gauss'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-6282913859151524575</id><published>2011-03-30T11:31:00.000-05:00</published><updated>2011-03-30T11:31:03.415-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><category scheme='http://www.blogger.com/atom/ns#' term='protocols'/><title type='text'>Frans Kaashoek wins the 2010 ACM-Infosys Foundation Award</title><content type='html'>According to ACM TechNews and the &lt;a href="http://web.mit.edu/newsoffice/2011/kaashoek-acm-award.html"&gt;MIT news&lt;/a&gt;, &lt;a href="http://pdos.csail.mit.edu/~kaashoek/"&gt;Frans Kaashoek&lt;/a&gt; has won the Association for Computing Machinery’s 2010 ACM-Infosys Foundation Award in the Computing Sciences. Prof. Kaashoek has done a lot of interesting distributed systems work and certainly deserves assorted awards. However, the weird part and what prompts this post is the specific award. According to &lt;a href="http://www.sdtimes.com/blog/post/ACM_AND_INFOSYS_FOUNDATION_HONOR_INNOVATOR_IN_SOFTWARE_SYSTEM_PERFORMANCE_SCALABILITY_AND_SECURITY/By_SD_Times_Newswire/35402"&gt;SD Times&lt;/a&gt; and the &lt;a href="http://awards.acm.org/homepage.cfm?awd=165"&gt;ACM&lt;/a&gt; itself, &lt;blockquote&gt;[the] &lt;a href="http://awards.acm.org/infosys"&gt;ACM-Infosys Foundation Award&lt;/a&gt;, established in August 2007, recognizes personal contributions by young scientists and system developers to a contemporary innovation that exemplifies the greatest recent achievements in the computing field. Financial support for the $150,000 award is provided by an endowment from the Infosys Foundation.&lt;/blockquote&gt;&lt;br /&gt;Specifically, notice the "young scientists and system developers" part. Kaashoek won the NSF national young investigator award in 1994 according to his page at MIT. He received his Ph.D. in 1992 under &lt;a href="http://www.cs.vu.nl/~ast/"&gt;Andy Tannenbaum&lt;/a&gt;. Heck, the earliest publication listed by him was in 1991. That would seem to make him roughly my age; certainly, it doesn't seem like he would be eligible for a &lt;a href="http://www.fields.utoronto.ca/aboutus/jcfields/fields_medal.html"&gt;Fields Medal&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So, congratulations to Frans! And maybe there is some hope for my aging carcass. I mean, if he is a "young scientist"....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-6282913859151524575?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/6282913859151524575/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=6282913859151524575' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6282913859151524575'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6282913859151524575'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/03/frans-kaashoek-wins-2010-acm-infosys.html' title='Frans Kaashoek wins the 2010 ACM-Infosys Foundation Award'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-2448139393785586609</id><published>2011-03-23T13:07:00.000-05:00</published><updated>2011-03-23T13:07:50.855-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><title type='text'>Quote o' the Day: Agressively stupid</title><content type='html'>This is from &lt;a href="http://www.theserverside.com/"&gt;TheServerSide.com's&lt;/a&gt; article, &lt;a href="http://www.theserverside.com/news/2240033465/Developers-still-skeptical-of-Oracles-stewardship-of-Java?asrc=EM_USC_13516094&amp;track=NL-461&amp;ad=818478&amp;"&gt;Developers still skeptical of Oracle’s stewardship of Java&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;James Gosling, considered the father of Java, said during his keynote session at the Java Symposium that it is in Oracle’s own interest to “not be really aggressively stupid.” But he said it’s been clear that Oracle didn’t exactly know what it was getting into with the acquisition of Java.&lt;/blockquote&gt;&lt;br /&gt;Not being really aggressively stupid is a problem to which many of us can relate.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-2448139393785586609?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/2448139393785586609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=2448139393785586609' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2448139393785586609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2448139393785586609'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/03/quote-o-day-agressively-stupid.html' title='Quote o&apos; the Day: Agressively stupid'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-7501784882314322422</id><published>2011-03-14T21:56:00.002-05:00</published><updated>2011-11-10T16:41:37.900-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>A few more comments about ...Why Is the Phone on Fire?</title><content type='html'>&lt;span style="float:right;margin:10px;"&gt;&lt;a href="http://www.amazon.com/gp/product/0750682183/ref=as_li_tf_il?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0750682183"&gt;&lt;img border="0" src="http://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL160_&amp;ASIN=0750682183&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=wwwcrsrnet-20&amp;ServiceVersion=20070822" &gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0750682183&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/span&gt;Since I gave such a ringing endorsement of &lt;em&gt;&lt;a href="http://www.amazon.com/gp/product/0750682183/ref=as_li_tf_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0750682183"&gt;If I Only Changed the Software, Why is the Phone on Fire?&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0750682183&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/em&gt; (at least as ringing as I plan on getting), there are a few more comments I can make related to the book.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Network protocols&lt;/h3&gt;&lt;br /&gt;&lt;table style="float:left; margin:10px;border:thin solid black;"&gt;&lt;tr style="text-align:center"&gt;&lt;th&gt;Header&lt;/th&gt;&lt;th&gt;Address&lt;/th&gt;&lt;th&gt;Message ID&lt;/th&gt;&lt;th&gt;Group ID&lt;/th&gt;&lt;th&gt;Data Length&lt;/th&gt;&lt;th&gt;Data&lt;/th&gt;&lt;th&gt;CRC&lt;/th&gt;&lt;tr&gt;&lt;tr style="text-align:center"&gt;&lt;td&gt;4 bytes&lt;/td&gt;&lt;td&gt;4 bytes&lt;/td&gt;&lt;td&gt;1 byte&lt;/td&gt;&lt;td&gt;1 byte&lt;/td&gt;&lt;td&gt;1 byte&lt;/td&gt;&lt;td&gt;0-27 bytes&lt;/td&gt;&lt;td&gt;2 bytes&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;One of Simone's chapters deals with a network-communication timing related bug that strikes somewhere close to my heart. Part of the problem deals with the format of protocol messages.&lt;br /&gt;&lt;br /&gt;&lt;table style="float:left; margin:10px;border:thin solid black;"&gt;&lt;tr&gt;&lt;th colspan="2"&gt;Raw Data Message Formats&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;Message Name/ID&lt;/th&gt;&lt;th&gt;Data Length&lt;/th&gt;&lt;th&gt;Data Format&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;DATA_CHAR/5&lt;/td&gt;&lt;td&gt;1 byte&lt;/td&gt;&lt;td&gt;Single char&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2"&gt;...&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;DATA_INT_ARRAY/11&lt;/td&gt;&lt;td&gt;1+(0-n)&lt;/td&gt;&lt;td&gt;Num ints (1 byte), raw int data&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2"&gt;...&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th colspan="2"&gt;Formatted Data Message Formats&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;Message Name/ID&lt;/th&gt;&lt;th&gt;Data Length&lt;/th&gt;&lt;th&gt;Data Format&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2"&gt;...&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BLOOD_PRESSURE/21&lt;/td&gt;&lt;td&gt;24&lt;/td&gt;&lt;td&gt;Timestamp, 10 samples&lt;br /&gt;bit-packed (4 chars, 1 int)&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2"&gt;...&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;This format has &lt;em&gt;a lot&lt;/em&gt; of excess redundancy. Consider that the data length is encoded in the message &lt;em&gt;three&lt;/em&gt; times: as the message id, as the data length itself, and sometimes in the data itself. For example, the raw integer array includes a total data length as well as the number of integers. On the other hand, the raw messages are irrelevant; any actual use is going to need a dedicated message id, and the id determines the data size. Further, the data size may also be in the header, as an overall message length, and in the CRC, because anything that goes on the wire, or in the air, needs to be checksummed.&lt;br /&gt;Since a part of the problem being discussed is a tight network-bandwidth bound, ditching the useless data length byte plus an unused byte in the data would allow another sample to be sent in the pulse-oxygen message, reducing the original bandwidth used from 120kbps and the solution's 29kbps to 27kbps, a reduction of about 6%.&lt;br /&gt;&lt;br /&gt;(Strangely, Simone cites &lt;a href="http://www.tinyos.net"&gt;TinyOS&lt;/a&gt; in the discussion of the message format. I have no idea why.)&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Tips&lt;/h3&gt;&lt;br /&gt;Despite providing another example of the &lt;a href="http://en.wikipedia.org/wiki/Celestial_Emporium_of_Benevolent_Knowledge%27s_Taxonomy"&gt;Heavenly Emporium of Benevolent Knowledge&lt;/a&gt;, Simone's list of tips has some interesting features.&lt;br /&gt;&lt;br /&gt;&lt;span style="float:left;margin:10px"&gt;&lt;a href="http://www.amazon.com/gp/product/0932633420/ref=as_li_tf_il?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0932633420"&gt;&lt;img border="0" src="http://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL160_&amp;ASIN=0932633420&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=wwwcrsrnet-20&amp;ServiceVersion=20070822" &gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0932633420&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/span&gt;&lt;h4&gt;Find a sounding board (doesn't have to be a live person!) - talk through ideas to quickly identify good ideas and discard bad ones.&lt;/h4&gt;Surprisingly effective. Also found in &lt;em&gt;&lt;a href="http://www.amazon.com/gp/product/0932633420/ref=as_li_tf_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0932633420"&gt;The Psychology of Computer Programming&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0932633420&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/em&gt;, where Gerald Weinberg advised talking to a stuffed bear. Or you can try a rubber duck, according to Del.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Use visual aids (flowcharts, graphs, function call trees)....&lt;/h4&gt;&lt;blockquote&gt;The opposite of a correct statement is a false statement. But the opposite of a profound truth may well be another profound truth. - Niels Bohr.&lt;/blockquote&gt;I come from the land of Dijkstra, where flowcharts and such are frowned on, for good reason. However, visual aids can easily show parallel structures, or the lack thereof, in the system.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Play Computer.&lt;/h4&gt;Or don't. As I may have mentioned before, I view dynamic reasoning with roughly the same enthusiasm as flowcharts. Both have their uses, but static reasoning and more formal methods are usually more effective.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Think with your brain, not your debugger.&lt;/h4&gt;My disdain for debuggers occasionally earns me abuse, but they really should be a last resort, not a first choice.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Be clever.&lt;/h4&gt;I reiterate my earlier reference to Niels.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-7501784882314322422?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/7501784882314322422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=7501784882314322422' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7501784882314322422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7501784882314322422'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/03/few-more-comments-about-why-is-phone-on.html' title='A few more comments about ...Why Is the Phone on Fire?'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-1549365327560331424</id><published>2011-03-11T20:54:00.001-06:00</published><updated>2011-11-10T16:42:26.971-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>If I Only Changed the Software, Why Is the Phone on Fire?</title><content type='html'>&lt;span style="float:right;margin:10px"&gt;&lt;a href="http://www.amazon.com/gp/product/0750682183/ref=as_li_tf_il?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0750682183"&gt;&lt;img border="0" src="http://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL160_&amp;ASIN=0750682183&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=wwwcrsrnet-20&amp;ServiceVersion=20070822" &gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0750682183&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/span&gt;I just returned from a vacation having read &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0750682183/ref=as_li_tf_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0750682183"&gt;If I Only Changed the Software, Why is the Phone on Fire?: Embedded Debugging Methods Revealed&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0750682183&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;, by Lisa Simone. I have to admit that this is not a great book; it did nothing to change the way I think and I don't remember seeing anything that I had not seen (or done) before. However, it is a pretty nice introduction to the subtle skill of debugging.&lt;br /&gt;&lt;br /&gt;Debugging is a difficult thing to teach. In fact, it seems to me to be more difficult to teach than to learn: I have never seen an attempt to teach debugging succeed on any greater level than a list of tips and rules of thumb. On the other hand, the most successful debuggers, and the most effective debugging efforts, have completely transcended any tips or rules. The person doing the debugging coupled a deep (if not specific) understanding of the system or at least technology in question with the problematic behavior to arrive on the trail of the problem almost mystically.&lt;br /&gt;&lt;br /&gt;Of the works that try to present a more thorough approach to debugging than a list of tips, many that come to mind attempt to teach a simplified, corrupted version of the scientific method: hypothesis followed by test; hypothesis, test; hypothesis, test. Unfortunately, without some significant guidance on the hypothesis phase, that method boils down to guess-and-hack, which is horribly inefficient. The whole art of debugging is in determining a likely, or at least useful, hypothesis.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;If I Only Changed the Software...&lt;/i&gt; does not try to present a grand theory of debugging, and it does have a list of tips, but it does more to teach the &lt;i&gt;feeling&lt;/i&gt; of debugging than any other work I've read. Perhaps the fictional, narrative-based style can teach what the process of debugging looks like.&lt;br /&gt;&lt;br /&gt;One nice (although someone else may feel otherwise) feature of the book is the use of, well, less than perfect code in examples. Certainly, when I was less experienced than I am now, I would have found the code a ghastly horror and a crime against nature. In fact, I would probably have been right. On the other hand, having seen more code, I now view the examples in the book as pretty typical. Certainly, none of it is &lt;a href="http://www.procmail.org/"&gt;procmail&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The big benefit of the code is that it demonstrates &lt;i&gt;a&lt;/i&gt; bug may not be &lt;i&gt;the&lt;/i&gt; bug. For example, the following is taken (and simplified) from one of the book's examples:&lt;br /&gt;&lt;pre&gt;/*&lt;br /&gt;   Function: Part of ISR. Every 1000 ms the new ovenPW is calculated.&lt;br /&gt; */&lt;br /&gt;void periodic_timer()&lt;br /&gt;{&lt;br /&gt;  /* ------ 10 msec ------ */&lt;br /&gt;  ... code ...&lt;br /&gt;  /* ------ 1000 msec ------ */&lt;br /&gt;  ten_msec_ctr++;&lt;br /&gt;  if (ten_msec_ctr == 10)&lt;br /&gt;  {&lt;br /&gt;    ...&lt;br /&gt;    ovenPW = ...&lt;br /&gt;    ten_msec_ctr = 0;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The function periodic_timer appears to be called every ten milliseconds. The bug I immediately spotted involves the code labeled with "1000 msec"; it is actually executed every 100 milliseconds. However, that issue is completely unrelated to the bug described in the chapter. Updating the oven-heater-on pulse width ten times more frequently than expected should not have any particular ill effects, certainly nothing involving the actual problem. That is a vital lesson for anyone doing debugging.&lt;br /&gt;&lt;br /&gt;I would recommend &lt;i&gt;If I Only Changed the Software...&lt;/i&gt; to just about any programmer, certainly anyone inexperienced in the task that has occupied much of my career. Although at least some exposure to low-level programming would be good, embedded programming experience is not a requirement. The book may be focused on embedded debugging, but the lessons are applicable to any programming task.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-1549365327560331424?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/1549365327560331424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1549365327560331424' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1549365327560331424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1549365327560331424'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/03/if-i-only-changed-software-why-is-phone.html' title='If I Only Changed the Software, Why Is the Phone on Fire?'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-31683724397326251</id><published>2011-03-06T10:50:00.000-06:00</published><updated>2011-03-06T10:50:02.230-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='toy problems'/><category scheme='http://www.blogger.com/atom/ns#' term='electronics'/><title type='text'>A paean to the pulldown resistor</title><content type='html'>As a Computer Sciences sophomore or junior (it has been so long I don't remember) at UT Austin, I took a class on basic digital logic (&lt;a href="http://projects.ece.utexas.edu/ee316/"&gt;EE316&lt;/a&gt;; I think they're using a later edition of the same textbook). What I learned there has not materially helped me any itself, although it provided an excellent base for later architecture and operating systems classes, and gosh knows I have used those a lot, in later classes, in research, and in actual productive work.&lt;br /&gt;&lt;br /&gt;On the other hand, I just acquired and started fiddling with an &lt;a href="http://www.arduino.cc/"&gt;Arduino&lt;/a&gt; and its excellent tutorials, especially &lt;a href="http://www.ladyada.net/learn/arduino/"&gt;Limor Fried's Arduino Tutorial: Learn Electronics using Arduino!&lt;/a&gt; (one of &lt;a href="http://www.adafruit.com/blog/2011/03/02/10-women-who-secretly-control-the-internet/"&gt;the 10 women who secretly control the Internet&lt;/a&gt;). And I just learned something basic, something that I did not have a clue about before.&lt;br /&gt;&lt;br /&gt;&lt;img style="float:left;margin:10px" src="http://www.crsr.net/images/Pulldown_Resistor.png"&gt;&lt;br /&gt;&lt;br /&gt;When you connect a switch to a digital logic input, such as a pin on a microcontroller programmed to turn on a LED when the switch is closed, you actually only have half of the work done. Consider the top half of Wikipedia's diagram to the left: if the switch is closed, the Logic Gate (representing my microcontroller pin) will see a voltage \(V_{in}\). \(V_{in}\) will normally be provided at a value that the microcontroller can interpret as 1, say, and work properly. On the other hand, as I recently learned, when the switch is open, the Logic Gate will see neither a 1 nor a 0; instead, it will see some odd, floating, unconnected value. In my Arduino experience, the LED will be in a weird, half-lit state, presumably switching on and off as the value fluctuates.&lt;br /&gt;&lt;br /&gt;What needs to be added is a connection to Ground, the 0 state, that takes over the input when the switch is closed. Unfortunately, if you connect the input to ground, it will be grounded whether or not the switch is open. So, you add the pulldown resistor, which allows the input state to go to 0 when the switch is open but which prevents the input from going to 0 when the switch is closed.&lt;br /&gt;&lt;br /&gt;Anyway, here's a tip of the hat to the humble pulldown resistor and the opposite, pullup resistor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-31683724397326251?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/31683724397326251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=31683724397326251' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/31683724397326251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/31683724397326251'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/03/paean-to-pulldown-resistor.html' title='A paean to the pulldown resistor'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-1992382326596804316</id><published>2011-02-01T21:47:00.007-06:00</published><updated>2011-02-01T21:47:00.290-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>The one problem with open source</title><content type='html'>[Corey, of &lt;a href="http://soupinadeli.com/"&gt;Soup In A Deli&lt;/a&gt;, pointed this out to me this morning, but it was such a disturbing thought that I immediately had to write this post.]&lt;br /&gt;&lt;br /&gt;What is the worst problem with open source software? It would have to be a completely inescapable problem, one which cannot be resolved while the software remains open source, as well as a problem restricted entirely to open source, one which simply cannot apply to any of the various forms of proprietary software.&lt;br /&gt;&lt;br /&gt;Let me pause here a minute and let you ponder the question....&lt;br /&gt;&lt;br /&gt;The usual suspects are right out. Documentation? Most reasonably popular open source projects have documentation at least as accessible as &lt;a href="http://www.oracle.com/technetwork/indexes/documentation/index.html"&gt;Oracle's&lt;/a&gt;, &lt;a href="http://www.ibm.com/support/entry/portal/Documentation"&gt;IBM's&lt;/a&gt;, or &lt;a href="http://msdn.microsoft.com/en-us/default"&gt;Microsoft's&lt;/a&gt;. Quality? It has been &lt;a href="http://pages.cs.wisc.edu/~bart/fuzz/fuzz.html"&gt;two decades&lt;/a&gt; since &lt;em&gt;that&lt;/em&gt; one went out the window. Usability? &lt;a href="http://www.codinghorror.com/blog/2006/02/sometimes-a-word-is-worth-a-thousand-icons.html"&gt;Nah.&lt;/a&gt; (Looks like Atwood's got some broken links.)&lt;br /&gt;&lt;br /&gt;No, the worst problem with open source software is...let me draw you a picture. If you're like me, and I know I am, you are a contractor working in a biggish enterprise shop. You probably have service level agreements as part of the contract, but unlike me, you probably have not just converted to a fixed-price contract, putting teeth into those SLA's. Suppose a problem rears its head, a mean one. A not-fixable-within-the-SLA-period problem.&lt;br /&gt;&lt;br /&gt;If you are using proprietary software, it's vendor time (if not Miller time). Generally, the SLA timer is going to have to be put on hold while you wait for a response from the vendor. If your shop has planned ahead, you will have a SLA with the vendor, but I have never seen any agreements that were coordinated, so that any problem requiring vendor involvement was guaranteed to be handled within the local SLA period. So, while you are waiting for the vendor to get back to you, the clock waiting for your performance has to be stopped. You have time to cast around for the actual solution to the problem. You have time to find a suitable scapegoat. You might even have time for lunch. So, even if the vendor comes back with a "Not me!" response, you have extra time to come up with a convenient work-around.&lt;br /&gt;&lt;br /&gt;But if you are using open source software, you are in a completely different boat. This time, without a paddle. In the worst case, you don't have anyone to point the finger at. A mailing list? Sure, I'll let you give that a try. Besides, I bet you sold the open source software with the promise that "I could fix it myself if I had to." Now, you have people looking at you with that annoying "Well?" expression. The only person you can point the finger at is yourself, and the timer is still running.&lt;br /&gt;&lt;br /&gt;I suppose this is why managers seem so interested in "indemnification" from vendors supporting open source software. Unfortunately, I'm neither a manager nor a weasel (to the extent that that is not redundant), so I never really understood it before. I'm one of the people who just has to make it work, which is why I like open source; the baggage that comes with proprietary vendors is tremendous and very, very ugly.&lt;br /&gt;&lt;br /&gt;So, there's your problem with open source software. If you are only interested in getting work done, open source is great. On the other hand, if you are interested in making money whether or not work gets done, open source software has a big problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-1992382326596804316?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/1992382326596804316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1992382326596804316' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1992382326596804316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1992382326596804316'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/02/one-problem-with-open-source.html' title='The one problem with open source'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-5732735204553137349</id><published>2011-01-28T15:55:00.001-06:00</published><updated>2011-01-28T16:05:48.342-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='link'/><category scheme='http://www.blogger.com/atom/ns#' term='data structure'/><title type='text'>What Every Computer Scientist Should Know About Floating-Point Arithmetic</title><content type='html'>According to &lt;a href="http://www.reddit.com/r/programming/comments/f9z15/with_its_urlcrapping_oracle_has_just_killed_the/"&gt;this post on reddit&lt;/a&gt;, Oracle has broken the links to "What Every Computer Scientist Should Know About Floating-Point Arithmetic", originally published in the March 1991 issue of the ACM's &lt;em&gt;Computing Surveys&lt;/em&gt;. Oddly enough, that is the only issue of &lt;em&gt;Computing Surveys&lt;/em&gt; that I own, having stolen a copy from someone at UTCS for just that article.&lt;br /&gt;&lt;br /&gt;In any case, lest it be lost entirely in the depths of Oracle's documentation, I grabbed a copy of &lt;a href="http://www.crsr.net/files/floating_point_math.pdf"&gt;"What Every Computer Scientist Should Know About Floating-Point Arithmetic"&lt;/a&gt; without any permission whatsoever simply because everyone (not just computer scientists) who deals with floating-point numbers really ought to have some kind of grasp of the stuff in this paper.&lt;br /&gt;&lt;br /&gt;(Of course, if Oracle sends me a cease-and-desist, I'll probably collapse like a soggy waffle.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5732735204553137349?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/5732735204553137349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5732735204553137349' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5732735204553137349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5732735204553137349'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/01/what-every-computer-scientist-should.html' title='What Every Computer Scientist Should Know About Floating-Point Arithmetic'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-6624045663098164199</id><published>2011-01-06T21:38:00.000-06:00</published><updated>2011-11-17T10:59:11.416-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='notation'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Orthogonality</title><content type='html'>This is a story about how bad code gets written by someone who knows better.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.crsr.net/images/orthogonal.png" imageanchor="1" style="border: thin solid black; clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.crsr.net/images/orthogonal.png" /&gt;&lt;/a&gt;&lt;/div&gt;Orthogonality, in a basic geometrical definition, means that two lines are perpendicular to each other. Consider the traditional x and y axes as the two lines. These two lines are perpendicular, and so orthogonal. All of the points on the y axis, projected onto the x axis, share the same point. If you move from one point on the y axis to another, you keep the same x value; your shadow on the x axis does not move.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.crsr.net/images/nonorthogonal.png" imageanchor="1" style="border: thin solid black; clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://www.crsr.net/images/nonorthogonal.png" /&gt;&lt;/a&gt;&lt;/div&gt;The alternative involves having the two lines non-perpendicular. Now, all of the points on the y axis, projected on the x axis, are mapped to different points on the x axis. If you move from one point on the y axis to another, you also have to change your x value; the shadow on the x axis moves with you.&lt;br /&gt;&lt;br /&gt;What has this got to do with bad code? Non-orthogonality is a problem when it appears in code. In this case, I could have avoided the problem, but I didn't. Now, I get to write bad code. It will work, but it will not be pretty, and I bet it will cause problems in the future.&lt;br /&gt;&lt;br /&gt;Take a pretty normal user authorization system, where users have the ability to perform their designated operations for the site where they work. As a result, the user's home location maps to their authorization. Unfortunately, it never stays that way. In my case, one group of users is authorized to do things for remote sites, and a sub-group of them &lt;i&gt;cannot&lt;/i&gt; do things for their own site. So, location no longer cleanly maps to authorization.&lt;br /&gt;&lt;br /&gt;One proposal was to use location as the primary authorization mechanism, with group membership overriding the location for the special cases. My proposal, on the other hand, was to use a group for every location and add users to the correct group to allow them to do whatever they need to do. Unfortunately, I didn't press the issue and it is too late now, given that the special groups are set up and populated and the sheer inertia of the organization is overwhelming.&lt;br /&gt;&lt;br /&gt;So I am now writing code using location as a primary authorization field with group membership as an override. Yay.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-6624045663098164199?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/6624045663098164199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=6624045663098164199' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6624045663098164199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6624045663098164199'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2011/01/orthogonality.html' title='Orthogonality'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-6839541873798942364</id><published>2010-12-27T12:59:00.001-06:00</published><updated>2010-12-27T13:01:03.747-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><title type='text'>Quote o' the Day: Appropriate shoes for protection from electrostatic charge</title><content type='html'>I was recently pointed by a cow-orker to the &lt;a href="http://pipeline.corante.com/archives/things_i_wont_work_with/"&gt;Things I won't work with&lt;/a&gt; segment of Derek Lowe's &lt;a href="http://pipeline.corante.com/"&gt;In the Pipeline&lt;/a&gt; blog, which includes some great comments like,&lt;br /&gt;&lt;blockquote&gt;"The paper mentions that 'Introducing N-oxides onto the tetrazole ring  may . . . push the limits of well-explored tetrazole chemistry into a  new, unexplored, dimension.', but (of more immediate importance) it may also push pieces of your lab equipment into unexplored parts of the far wall."&lt;/blockquote&gt;&amp;nbsp;and&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Our noses can &lt;i&gt;immediately&lt;/i&gt; tell the difference between garden  variety nitriles and their evil twins [isonitriles]. The former often have no smell at  all, or run to a faint spicyness. The latter smell like. . . like. .  .well, I've never actually been downwind of the Abominable Snowman's  armpit or been had my eyeglasses fogged up by a Komodo dragon with  stomach trouble, but those are the examples that come to mind.&lt;/blockquote&gt;&lt;br /&gt;But my favorite is a quote from one of the &lt;a href="http://pipeline.corante.com/archives/2010/10/14/whoa_time_to_clean_the_fishtank_uh_root_canal_appointment_look_at_the_time.php"&gt;papers&lt;/a&gt; mentioned:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;"The use of suitable protective clothing, in particular a face shield, ear protectors, a bullet-proof vest, arm protectors, and kevlar gloves, as well as appropriate shoes for protection from electrostatic charge, is mandatory. Ignoring these safety precautions can result in serious injury!"&lt;/blockquote&gt;&lt;br /&gt;And I thought my life was difficult when I had to wear a &lt;a href="http://www.tasco-safety.com/hhats/Cowboy-hard-hats.html"&gt;hard-hat&lt;/a&gt; because I was dealing with emacs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-6839541873798942364?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/6839541873798942364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=6839541873798942364' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6839541873798942364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/6839541873798942364'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2010/12/quote-o-day-appropriate-shoes-for.html' title='Quote o&apos; the Day: Appropriate shoes for protection from electrostatic charge'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-4994975956125664345</id><published>2010-12-25T18:53:00.000-06:00</published><updated>2010-12-25T18:53:16.542-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='notation'/><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='Dijkstra'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>Equational programming</title><content type='html'>&lt;em&gt;It is Christmas and Dr. McGuire is too busy watching snow fall to come up with a real post, so he is just rehashing a reply to a question on the &lt;a href="http://www.haskell.org/mailman/listinfo/beginners"&gt;haskell-beginners mailing list&lt;/a&gt; as if it were new. Typical.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Jun HU wrote:&lt;br /&gt;&lt;blockquote&gt;My first language is C, and I've strong intention in learning a pure functional programming language. My very first question is how to think in the functional programming way, anyone has some ideas.&lt;/blockquote&gt;&lt;br /&gt;I cannot claim C as my &lt;em&gt;first&lt;/em&gt; language, but I do say it is my "natural" language; I have written more code in C than I have in any other, and I've been using it for nigh on 20 years. I also cannot claim to think in &lt;em&gt;the&lt;/em&gt; functional programming way, but using O'Caml and Haskell has definitely changed how I program in any language. In fact, I suspect functional programming has had a bigger effect than I had previously considered. But I am definitely not a Haskell guru.&lt;br /&gt;&lt;br /&gt;I believe the biggest difference between functional and procedural programming is thinking equationally rather than operationally. With procedural programming as in C (and most object oriented languages, which in my experience are more procedural than not), the tendency is to think  operationally: "First the program does this, then that happens, then that,...." Now, back at UT Austin (I grew up in the land of Dijkstra), at the time anyway, they were fond of teaching axiomatic thinking: "At this point in the program text, the state is this; at that point in the text, the state is that...." That is definitely a significant improvement, and I attribute what decent code I have written to that approach, but it definitely is not as natural as either operational or equational thinking.&lt;br /&gt;&lt;br /&gt;Thinking operationally (or "pretending to be the computer") is problematic because there are typically an exponential number of paths through a program. As a result, it is impossible to completely understand even middling small program. Further, operational approaches provide no particularly good strategies for developing programs.&lt;br /&gt;&lt;br /&gt;If you can get past the initial visceral revulsion at the thought of &lt;em&gt;proving programs correct&lt;/em&gt; (Horrors!), thinking axiomatically has significant benefits. On one hand, it reduces the exponential number of paths through the program to a linear number of positions in the program text. For example, if you have a block of program text &lt;em&gt;s&lt;/em&gt; which, in a program state &lt;em&gt;p&lt;/em&gt; is guaranteed to arrive at another state &lt;em&gt;q&lt;/em&gt;, and likewise program text &lt;em&gt;t&lt;/em&gt; going from &lt;em&gt;q&lt;/em&gt; to &lt;em&gt;r&lt;/em&gt;, then you have &lt;em&gt;s;t&lt;/em&gt; going from &lt;em&gt;p&lt;/em&gt; to &lt;em&gt;r&lt;/em&gt;; it doesn't matter what happens in the middle. Further, axiomatic thinking does provide some guidance to writing code: if you think you need a conditional statement, then you want to go from &lt;em&gt;p&lt;/em&gt; to some narrow, definite state &lt;em&gt;q&lt;/em&gt;; if you need a loop, then you can look for an invariant and a termination condition. Not easy, but there is &lt;em&gt;something&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;On the other hand, in functional languages (and also when taking functional approaches in a non-functional language), it is very important to think equationally: "This means that; this other thing is that...." This is especially true in Haskell, which is &lt;em&gt;not strict&lt;/em&gt;; if you try to think operationally or even axiomatically, you run into difficulties when the state of a non-strict program does not resemble the state of a strict program.&lt;br /&gt;&lt;br /&gt;Equational thinking completely does away with the "number of paths" argument. A functional definition is, or should be, small enough to understand directly, based on any underlying definitions. Further, because the state does not change (in operational terms, or equivalently in axiomatic terms, there is only one state), it becomes less important to manipulate the program as a whole. Instead each definition can be dealt with separately.&lt;br /&gt;&lt;br /&gt;Now, equational thinking is easy for stuff like&lt;br /&gt;&lt;br /&gt;\[\textbf{add_one}\ n = n + 1\]&lt;br /&gt;&lt;br /&gt;But it is not immediately apparent how that extends to something that needs recursion, say. The big "Ah-ha!" moment for me was the realization that recursion and mathematical induction are the same thing (ok, it's not a surprise for anyone; the big deal was when I internalized it enough to use the idea to naturally write code). With that, you can deal with anything programmatically equational and recursive as mathematically equational and inductive. The change in thinking is as big as the difference between operational and axiomatic.&lt;br /&gt;&lt;br /&gt;Equational thinking extends beyond basic function definitions; I think it is the key to the type system, classes, and most of the other neat language features. At this point, I am still struggling with category theory, although I have been able to make use of monads reasonably elegantly (in my (humble) opinion, of course). I think there is another step there, although I haven't made it. &lt;br /&gt;&lt;br /&gt;This is all rather fuzzy and exceptionally difficult to put into words. However, I am willing to change my traditional definition, &lt;strong&gt;Programming is applied formal logic&lt;/strong&gt;, to include at least abstract algebra and category theory at this point, though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-4994975956125664345?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/4994975956125664345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=4994975956125664345' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4994975956125664345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4994975956125664345'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2010/12/equational-programming.html' title='Equational programming'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-5168193354962543065</id><published>2010-12-15T14:36:00.000-06:00</published><updated>2010-12-15T14:36:10.451-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><title type='text'>Speaking of Peano arithmetic...</title><content type='html'>&lt;blockquote&gt;&lt;i&gt;Objection 8.&lt;/i&gt; Peano's axioms are clearly nonsense: Let &lt;i&gt;f&lt;/i&gt; be a bijection from the supposed \(N_0\) to a set of filing cabinets. Lock &lt;i&gt;f(0)&lt;/i&gt; and put the key in &lt;i&gt;f(1)&lt;/i&gt;, lock &lt;i&gt;f(1)&lt;/i&gt; and put the key in &lt;i&gt;f(2)&lt;/i&gt;, and continue by induction. Now all the cabinets are locked, with their keys locked inside their neighbors. That is obviously impossible. Hence \(N_0\) does not exist.&lt;/blockquote&gt;&lt;blockquote&gt;&amp;nbsp;&lt;i&gt;Reply to Objection 8.&lt;/i&gt; Filing cabinets are not mathematics.&lt;/blockquote&gt;&lt;br /&gt;"Arithmetic", &lt;i&gt;Mathematics Made Difficult&lt;/i&gt;. Carl E. Linderholm, The World Publishing Company, 1971; p. 19.&lt;br /&gt;&lt;br /&gt;In other news, I just discovered the worst idiocy I have ever perpetrated in a programming language. For some obscure reason, it apparently seemed a good idea at the time to write,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;raStr != null ? "false".equalsIgnoreCase(raStr) : true;&lt;/pre&gt;&lt;br /&gt;As a result, to get this particular parameter to evaluate to false, I need to set the argument to some string &lt;i&gt;other&lt;/i&gt; than "false". Nice. Good one there, Tommy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-5168193354962543065?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/5168193354962543065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=5168193354962543065' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5168193354962543065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/5168193354962543065'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2010/12/speaking-of-peano-arithmetic.html' title='Speaking of Peano arithmetic...'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-1954312686677208868</id><published>2010-12-11T21:01:00.004-06:00</published><updated>2010-12-15T10:25:26.222-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><category scheme='http://www.blogger.com/atom/ns#' term='data structure'/><title type='text'>Measured Finger Trees</title><content type='html'>As I wrote a couple of weeks ago about &lt;a href="http://maniagnosis.crsr.net/2010/11/finger-trees.html"&gt;Finger Trees&lt;/a&gt;, &lt;br /&gt;&lt;blockquote&gt;Finger trees combine several features that make them incredibly useful, including [functional] purity, flexibility, efficiency, and simplicity.&lt;/blockquote&gt;A large portion of those advantages spring from the structure of the finger trees themselves, which provide efficient, purely functional deque operations and concatenation. While I was working on completing my finger tree implementation, I began to wonder how it achieved its efficiency, specifically the efficient concatenation. Hinze and Paterson say,&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;It is easy to check that in each of the invocations of [foldWings], the list argument has length at most 4, so each of these invocations takes Θ(1) time. The recursion terminates when we reach the bottom of the shallower tree, with up to 4 insertions, so the total time taken is Θ(log(min{&lt;i&gt;n1&lt;/i&gt; ,&lt;i&gt; n2&lt;/i&gt;})), where &lt;i&gt;n1&lt;/i&gt; and &lt;i&gt;n2&lt;/i&gt; are the numbers of elements in the argument trees.&lt;/blockquote&gt;...which is a little too telegraphic for me. The problem is that, in order to get the log n behavior, the tree must be balanced, and no operation in building the finger tree explicitly keeps the tree balanced. Then, I realized that the the structure of the tree it self performed that magic.&lt;br /&gt;&lt;br /&gt;Consider a normal binary tree where each node has a data element and two children, and the element in the node is greater than any value under its left child and less than any value under its right child. If the tree is &lt;i&gt;complete&lt;/i&gt;, then it is balanced; every internal node has two children, so an operation that traverses from the root of the tree to a specific leaf visits log n nodes. However, if the tree was built from a sorted sequence with no effort at keeping it balanced will structurally resemble a linked list, and an operation attempting to find a specific node will visit n nodes. As a result, with no effort to keep the tree balanced, the worst-case behavior of tree operations will be O(n), not O(log n).&lt;br /&gt;&lt;br /&gt;So, what does it mean to be &lt;i&gt;balanced&lt;/i&gt;? There are several possibilities; a complete tree is obviously balanced. For finger trees, however, I think the best definition lies in the number of elements at a depth &lt;i&gt;k&lt;/i&gt; as compared to depth &lt;i&gt;k-1&lt;/i&gt;. For example, continuing with the complete binary tree, the number of elements at depth 0 is 1, the root element. The number of elements at depth 1 is 2; the number at depth 2 is 4; and the number at depth 3 is 8. &lt;i&gt;The number of elements grows exponentially with depth.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Now look at the structure of the finger tree. The spine of the finger tree, where the depth of the structure lies, is not made of a collection of elements, but a collection of 2-3 tree Nodes of the elements of the current level. To put it another way, the first layer of the finger tree contains elements of type T, in the Empty or Single form or in the two Digits; the second layer contains Node&amp;lt;T&amp;gt; elements, and the third layer contains Node&amp;lt;Node&amp;lt;T&amp;gt;&amp;gt; elements. Now, assume that the tree is made entirely of instances of Deep, with a terminal spine of Empty, and that the digits are minimal, in the sense of having the fewest possible contents. At depth 0 are 2 elements of type T. At depth 1 are two elements of type Node&amp;lt;T&amp;gt;, each containing at least 2 elements of type T for a total of at least 4 elements of type T. At depth 2 are two elements of type Node&amp;lt;Node&amp;lt;T&amp;gt;&amp;gt;, containing a total of 8 elements of type T.&lt;br /&gt;&lt;br /&gt;As a result of its structure, even in the case of this minimal tree, &lt;i&gt;the number of elements grows exponentially with depth.&lt;/i&gt; The finger tree is balanced by its structure with no explicit operations to keep it balanced.&lt;br /&gt;&lt;br /&gt;Of course, part of that structure is the guarantee that only elements at each end are easily accessible. But the other half of the finger tree remedies that....&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Measurement&lt;/h2&gt;&lt;br /&gt;I have no intention of trying to provide an insightful lesson into the use of monoids, which when combined with the finger tree make the data structure a very powerful too. For that, check out &lt;a href="http://apfelmus.nfshost.com/articles/monoid-fingertree.html"&gt;Monoids and Finger Trees&lt;/a&gt; by Heinrich Apfelmus. Instead, I intend to just describe how the monoids and measures work with the Java finger trees.&lt;br /&gt;&lt;br /&gt;What is a monoid? On one hand, it is a triple of a set of values, called a carrier set, an operation which is closed in the carrier set as well as being associative, and a specific value from the carrier set which is an identity. On another hand, it is an implementation of the following interface.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public interface Monoid&amp;lt;T&amp;gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; public T zero();&lt;br /&gt;&amp;nbsp; public T plus(T l, T r);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;With, of course the same property requirements and where T is the carrier set.&amp;nbsp; For a standard example of monoids, there are&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp; public static class IntegerAdd implements Monoid&amp;lt;Integer&amp;gt;&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override public Integer plus(Integer l, Integer r) { return l + r; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override public Integer zero() { return 0; }&lt;br /&gt;&amp;nbsp; }&lt;/pre&gt;integers as the carrier set with addition as the operation and 0 as the identity form a monoid. Also, &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp; public static class IntegerMult implements Monoid&amp;lt;Integer&amp;gt;&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override public Integer plus(Integer l, Integer r) { return l * r; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override public Integer zero() { return 1; }&lt;br /&gt;&amp;nbsp; }&lt;/pre&gt;integers with multiplication (as "plus", the operation) and 1 (as the zero) form another monoid. ("&lt;i&gt;1 is the zero of multiplication.&lt;/i&gt;" I dedicate that sentence to my four (!) calculus instructors at the University of Texas at Austin, who are probably rolling in their graves at the thought of me discussing mathematics (even though I don't think any of them are dead).)&lt;br /&gt;&lt;br /&gt;Anyway, with a monoid, the next thing I need to build is a Measure,&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public abstract class Measure&amp;lt;T, V&amp;gt; implements Monoid&amp;lt;V&amp;gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; public final Monoid&amp;lt;V&amp;gt; monoid;&lt;br /&gt;&amp;nbsp; public Measure(Monoid&amp;lt;V&amp;gt; monoid) { this.monoid = monoid; }&lt;br /&gt;&amp;nbsp; @Override public V plus(V v1, V v2) { return monoid.plus(v1, v2); }&lt;br /&gt;&amp;nbsp; public V plus(V v1, V v2, V v3) { return monoid.plus(v1, monoid.plus(v2, v3)); }&lt;br /&gt;&amp;nbsp; @Override public V zero() { return monoid.zero(); }&lt;br /&gt;&amp;nbsp; public abstract V measure(T t);&lt;br /&gt;}&lt;/pre&gt;A Measure&amp;lt;T,V&amp;gt; is a monoid over a carrier set V, based on a lower level monoid which is passed as an argument to the Measure's constructor. The measure adds two operations. One is a three-argument plus method, which is safe due to the properties of the monoid and very convenient. The other is the method measure, which takes an element of a type T and projects that element into the carrier set, V. To put that another way, measure constructs a tag value for the T element as required by the ultimate data structure being constructed from the finger tree.&lt;br /&gt;&lt;br /&gt;An example Measure is&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp; public static class Counter&amp;lt;T&amp;gt; extends Measure&amp;lt;T,Integer&amp;gt;&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Counter() { super(Monoids.INTEGER_ADD); }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override public Integer measure(T t) { return 1; }&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&lt;/pre&gt;The Counter projects elements of T into the carrier set Integer by returning 1; with the Integer addition monoid, this measure &lt;i&gt;counts&lt;/i&gt; the elements in a measured data structure.&lt;br /&gt;&lt;br /&gt;Following along Hinze and Paterson, Digits are relatively unchanged, although they do now carry a reference to a Measure used to compute measure tags for the Digit instances. Nodes, on the other hand, also carry a tag value&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp; public final V tag;&lt;/pre&gt;representing the measure of the contents of the Node. Likewise the Empty, Single, and Deep classes have tag fields. The tag of Empty is the zero of the monoid, while Single and Deep are tagged with the plus-combination of the tags of the contained elements.&lt;br /&gt;&lt;br /&gt;Besides managing the tag values, what can you do with a measured finger tree? How about splitTree?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp; public abstract Split&amp;lt;MeasuredFingerTree&amp;lt;T,V&amp;gt;,T,V&amp;gt; splitTree(Predicate&amp;lt;V&amp;gt; p, V i);&lt;/pre&gt;A Split of a finger tree is a triple containing two finger trees and a designated value. If you have a finger tree representing a sequence of elements \(t_i\) tagged with measures \(v_i\),&lt;br /&gt;\[ (t_0,v_0), (t_1,v_1), \ldots, (t_n,v_n) \]&lt;br /&gt;as well as a &lt;i&gt;monotonic&lt;/i&gt; predicate &lt;i&gt;p&lt;/i&gt; over V and an initial V value &lt;i&gt;i&lt;/i&gt;, splitTree creates a Split structure containing &lt;br /&gt;\[ [ (t_0,v_0), \ldots, (t_{j-1},v_{j-1}) ], t_j, [ (t_{j+1},v_{j+1}), \ldots, (t_n,v_n) ] \]&lt;br /&gt;where \(p(i + v_0 + \ldots + v_{j-1}) \equiv \textbf{false})\), but \(p(i + v_0 + \ldots + v_j) \equiv \textbf{true})\). In other words, splitTree divides the finger tree into a prefix where the predicate &lt;i&gt;p&lt;/i&gt; is false, a designated value where &lt;i&gt;p&lt;/i&gt; becomes true, and a suffix, where &lt;i&gt;p&lt;/i&gt; remains true if it is monotonic. (For more on monotonic predicates, see apfelmus' article; basically it means the predicate is false up to some value where it becomes true and remains true for all further values. All modulo the monoid, of course.)&lt;br /&gt;&lt;br /&gt;A predicate is an implementation of the interface&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public interface Predicate&amp;lt;V&amp;gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; public boolean apply(V v);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;and an example is&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;final int half = max/2;&lt;br /&gt;new Predicate&amp;lt;Integer&amp;gt;() { @Override public boolean apply(Integer v) { return half &amp;lt; v; } };&lt;br /&gt;&lt;/pre&gt;where max is the number of elements in a given collection. Given the Counter measure, this predicate can split a tree in half.&lt;br /&gt;&lt;br /&gt;The splitTree method is implemented by Empty as&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override public Split&amp;lt;MeasuredFingerTree&amp;lt;T,V&amp;gt;, T, V&amp;gt; splitTree(Predicate&amp;lt;V&amp;gt; p, V i) { throw new IndexOutOfBoundsException(); }&lt;/pre&gt;In other words, and Empty finger tree cannot be split. For Single, the implementation is&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Split&amp;lt;MeasuredFingerTree&amp;lt;T, V&amp;gt;, T, V&amp;gt; splitTree(Predicate&amp;lt;V&amp;gt; p, V i)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MeasuredFingerTree&amp;lt;T, V&amp;gt; empty = empty(measure);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new Split&amp;lt;MeasuredFingerTree&amp;lt;T, V&amp;gt;, T, V&amp;gt;(empty, t, empty);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;(Hinze and Paterson put some preconditions on the operation:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Note also that the preconditions \(\neg p.i\) and \(p.(i + t)\) are used only if the split occurs at one or other end of the sequence. Consequently, if we treat those cases specially it suffices to require that the initial tree t is non-empty....&lt;/blockquote&gt;which is reflected in the assumption that a Single element represents the right place to split.)&lt;br /&gt;&lt;br /&gt;For Deep instances, splitTree is&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Split&amp;lt;MeasuredFingerTree&amp;lt;T,V&amp;gt;,T,V&amp;gt; splitTree(Predicate&amp;lt;V&amp;gt; p, V i)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; final V vpr = measure.plus(i, left.measure());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (p.apply(vpr))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; final Split&amp;lt;Digit&amp;lt;T,V&amp;gt;,T,V&amp;gt; spl = left.splitDigit(p, i);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MeasuredFingerTree&amp;lt;T,V&amp;gt; prefix = empty(measure);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (T t : spl.prefix()) { prefix = prefix.addLast(t); }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; final MeasuredFingerTree&amp;lt;T,V&amp;gt; suffix = deep(spl.suffix(), spine, right);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new Split&amp;lt;MeasuredFingerTree&amp;lt;T,V&amp;gt;,T,V&amp;gt;(prefix, spl.current(), suffix);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; final V vm = measure.plus(vpr, spine.tag);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (p.apply(vm))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; final Split&amp;lt;MeasuredFingerTree&amp;lt;Node&lt;t,v&gt;, V&amp;gt;, Node&amp;lt;T,V&amp;gt;, V&amp;gt; splSpine = spine.splitTree(p, vpr);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; final Split&amp;lt;Digit&amp;lt;T,V&amp;gt;,T,V&amp;gt; splDigit&lt;/t,v&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = splSpine.current().toDigit().splitDigit(p, measure.plus(vpr, splSpine.prefix().tag));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; final MeasuredFingerTree&amp;lt;T,V&amp;gt; prefix = deep(left,splSpine.prefix(), splDigit.prefix());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; final MeasuredFingerTree&amp;lt;T,V&amp;gt; suffix = deep(splDigit.suffix(), splSpine.suffix(), right);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new Split&amp;lt;MeasuredFingerTree&amp;lt;T,V&amp;gt;,T,V&amp;gt;(prefix, splDigit.current(), suffix);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; final Split&amp;lt;Digit&amp;lt;T,V&amp;gt;,T,V&amp;gt; spl = right.splitDigit(p, vm);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MeasuredFingerTree&amp;lt;T,V&amp;gt; suffix = empty(measure);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (T t : spl.suffix()) { suffix = suffix.addLast(t); }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; final MeasuredFingerTree&amp;lt;T,V&amp;gt; prefix = deep(left, spine, spl.prefix());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return new Split&amp;lt;MeasuredFingerTree&amp;lt;T,V&amp;gt;,T,V&amp;gt;(prefix, spl.current(), suffix);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;The first branch is taken if the split point is in the left Digit, the second if the split point is in the spine, and the third if the split point is in the right Digit. The first and third branches are symmetric. The second branch first splits the spine (producing splSpine), then converts the designated element (which is a Node&amp;lt;T&amp;gt;, remember) to a Digit and splits it to get the designated element and partial prefixes and suffixes to be added to the original edge digit and the prefix and suffix spines. All three branches use a specialized Deep constructor, the deep method, which correctly handles the possibility of empty Digits. (Under normal circumstances, the invariant of Digits includes that they are non-empty.)&lt;br /&gt;&lt;br /&gt;Because of the balanced nature of the finger tree, this method can only recurse into the spine log n times; the other operations are constant time; as a result this method is O(log n).&lt;br /&gt;&lt;br /&gt;I will post links to the code soon, after I have played with it some more. In the mean time, I did find an implementation of finger trees in the &lt;a href="http://functionaljava.org/"&gt;Functional Java&lt;/a&gt; library.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-1954312686677208868?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/1954312686677208868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=1954312686677208868' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1954312686677208868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/1954312686677208868'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2010/12/measured-finger-trees.html' title='Measured Finger Trees'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-7107026802716086422</id><published>2010-12-09T18:30:00.001-06:00</published><updated>2010-12-09T18:30:00.884-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='toy problems'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='notation'/><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>More Phantom Types in Java</title><content type='html'>&lt;i&gt;Text unabashedly stolen from Ralf Hinze, &lt;a href="http://www.comlab.ox.ac.uk/people/ralf.hinze/talks/FOP.pdf"&gt;Fun with Phantom Types&lt;/a&gt;.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Introducing phantom types&lt;/h2&gt;&lt;br /&gt;&lt;blockquote&gt;Suppose you want to embed a simple expression language in Haskell. You are a firm believer of static typing, so you would like your embedded language to be statically typed, as well. This rules out a simple Term data type as this choice would allow us to freely mix terms of different types. Idea: parameterize the Term type so that Term \(\tau\) comprises only terms of type \(\tau\).&lt;br /&gt;&lt;br /&gt;Zero       :: Term Int&lt;br /&gt;Succ, Pred :: Term Int \( \rightarrow \) Term Int&lt;br /&gt;IsZero     :: Term Int \(\rightarrow\) Term Bool&lt;br /&gt;If         :: \(\forall\alpha\). Term Bool \(\rightarrow\) Term \(\alpha \rightarrow\) Term \(\alpha \rightarrow\) Term \(\alpha\)&lt;br /&gt;&lt;br /&gt;Alas, the signature above cannot be translated into a data declaration[...in un-extended Haskell 98. It can be done with &lt;a href="http://en.wikipedia.org/wiki/Generalized_algebraic_data_type"&gt;Generalized Abstract Data Types&lt;/a&gt;.]&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Idea:&lt;/strong&gt; augment the data construct by type equations that allow us to constrain the type argument of Term.&lt;br /&gt;\[&lt;br /&gt;\begin{equation}\begin{split}&lt;br /&gt;\textit{data}\ \textit{Term}\ \tau &amp;amp; = &amp;amp; \textit{Zero}\ &amp;amp; \textit{with}\ \tau = \textit{Int} \\&lt;br /&gt;&amp;amp; | &amp;amp; \textit{Succ (Term Int)} &amp;amp; \textit{with}\ \tau = \textit{Int} \\&lt;br /&gt;&amp;amp; | &amp;amp; \textit{Pred (Term Int)} &amp;amp; \textit{with}\ \tau = \textit{Int} \\&lt;br /&gt;&amp;amp; | &amp;amp; \textit{IsZero (Term Int)} &amp;amp; \textit{with}\ \tau = \textit{Bool} \\&lt;br /&gt;&amp;amp; | &amp;amp; \textit{If (Term Bool)} (\textit{Term}\ \alpha) (\textit{Term}\ \alpha) &amp;amp; \textit{with}\ \tau = \alpha&lt;br /&gt;\end{split}\end{equation}&lt;br /&gt;\]&lt;br /&gt;Thus, Zero has [type Term \(\tau\)] with the additional constraint \(\tau\) = Int.&lt;br /&gt;&lt;br /&gt;NB. The type variable  does not appear on the left-hand side; it can be seen as being &lt;strong&gt;existentially quantified&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Here is a simple interpreter for the expression language. Its definition proceeds by straightforward structural recursion. Even though eval is assigned the type \(\forall\tau.\textit{Term}\ \tau\rightarrow\tau\), each equation has a more specific type as dictated by the type constraints. The interpreter is quite noticeable in that it is tag free. If it receives a Boolean expression, then it returns a Boolean.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;I apologize for the &lt;a href="http://planetmath.org/encyclopedia/PeanoArithmetic.html"&gt;Peano arithmetic,&lt;/a&gt; but, really, it's not my fault.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  public static abstract class Term&amp;lt;T&gt;&lt;br /&gt;  {&lt;br /&gt;    public abstract T eval();&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public static class Zero extends Term&amp;lt;Integer&gt;&lt;br /&gt;  {&lt;br /&gt;    @Override public Integer eval() { return 0; }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public static class Succ extends Term&amp;lt;Integer&gt;&lt;br /&gt;  {&lt;br /&gt;    public final Term&amp;lt;Integer&gt; pred;&lt;br /&gt;    public Succ(Term&amp;lt;Integer&gt; pred) { this.pred = pred; }&lt;br /&gt;    @Override public Integer eval() { return 1 + pred.eval(); }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public static class IsZero extends Term&amp;lt;Boolean&gt;&lt;br /&gt;  {&lt;br /&gt;    public final Term&amp;lt;Integer&gt; i;&lt;br /&gt;    public IsZero(Term&amp;lt;Integer&gt; i) { this.i = i; }&lt;br /&gt;    @Override public Boolean eval() { return i.eval() == 0; }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public static class If&amp;lt;A&gt; extends Term&amp;lt;A&gt;&lt;br /&gt;  {&lt;br /&gt;    Term&amp;lt;Boolean&gt; test;&lt;br /&gt;    Term&amp;lt;A&gt; t, f;&lt;br /&gt;    public If(Term&amp;lt;Boolean&gt; test, Term&amp;lt;A&gt; t, Term&amp;lt;A&gt; f) { this.test = test; this.t = t; this.f = f; }&lt;br /&gt;    @Override public A eval() { return test.eval() ? t.eval() : f.eval(); }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public static     Term&amp;lt;Integer&gt; zero()                  { return new Zero(); }&lt;br /&gt;  public static     Term&amp;lt;Integer&gt; succ(Term&amp;lt;Integer&gt; i)   { return new Succ(i); }&lt;br /&gt;  public static     Term&amp;lt;Boolean&gt; isZero(Term&amp;lt;Integer&gt; i) { return new IsZero(i); }&lt;br /&gt;  public static &amp;lt;A&gt; Term&amp;lt;A&gt;       iff(Term&amp;lt;Boolean&gt; test, Term&amp;lt;A&gt; t, Term&amp;lt;A&gt; f)&lt;br /&gt;                                    { return new If&amp;lt;A&gt;(test, t, f); }&lt;br /&gt;&lt;br /&gt;  public static void main(String[] args)&lt;br /&gt;  {&lt;br /&gt;    Term&amp;lt;Integer&gt; iff = iff(isZero(succ(zero())), zero(), succ(zero()));&lt;br /&gt;    System.out.println(iff.eval());&lt;br /&gt;    // Fails to compile with: The method isZero(Eval.Term&amp;lt;Integer&gt;) in the type Eval is&lt;br /&gt;    // not applicable for the arguments (Eval.Term&amp;lt;Boolean&gt;)&lt;br /&gt;    // isZero(isZero(zero()));&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;blockquote&gt;The type Term \(\tau\) is quite unusual.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Term is not a container type: an element of Term Int is an expression that evaluates to an integer; it is not a data structure that contains integers.&lt;/li&gt;&lt;li&gt;We cannot define a mapping function \( (\alpha\rightarrow\beta) \rightarrow (\textit{Term}\ \alpha\rightarrow\textit{Term}\ \beta) \) as for many other data types.&lt;/li&gt;&lt;li&gt;The type Term \(\beta\) might not even be inhabited: there are, for instance, no terms of type Term String.&lt;/li&gt;&lt;/ul&gt;Since the type argument of Term is not related to any component, we call Term a &lt;strong&gt;phantom type&lt;/strong&gt;.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Hinze's definition of &lt;em&gt;phantom type&lt;/em&gt; is different from what I would call a phantom type. Instead of calling Term a phantom type, I would refer to Integer in Term&amp;lt;Integer&gt; as a phantom type, in the definition of Zero. In that case, although the return value of eval is an Integer, the type Integer does not play any other role in the structure of the Zero type. In other words, the type Integer does not appear on the &lt;em&gt;right-hand side&lt;/em&gt; of Zero values; nor does Boolean appear on the right-hand side of IsZero, except in the return value of eval.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-7107026802716086422?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/7107026802716086422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=7107026802716086422' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7107026802716086422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7107026802716086422'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2010/12/more-phantom-types-in-java.html' title='More Phantom Types in Java'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-8048186816288517125</id><published>2010-11-30T13:59:00.001-06:00</published><updated>2010-12-04T23:33:59.501-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><title type='text'>Quote o' the Day: Open sores</title><content type='html'>&lt;blockquote&gt;Being 'open source' is a sign that an operating system will be inexpensive, adaptable and far less restricted than a closed platform like iOS. Having open sores is a sign of severe medical / hygiene issues.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;From techeye.net, &lt;a href="http://www.techeye.net/software/nokias-meego-is-doomed"&gt;Nokia's MeeGo is doomed&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Thanks, Del.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-8048186816288517125?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/8048186816288517125/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=8048186816288517125' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/8048186816288517125'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/8048186816288517125'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2010/11/quote-o-day-open-sores.html' title='Quote o&apos; the Day: Open sores'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-7182364149692632927</id><published>2010-11-25T23:29:00.005-06:00</published><updated>2010-12-15T14:42:44.211-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><category scheme='http://www.blogger.com/atom/ns#' term='data structure'/><title type='text'>Finger Trees</title><content type='html'>I want to take a minute to &lt;a href="http://greatertuna.com/times/times3.htm"&gt;think about finger trees&lt;/a&gt;.[1]&lt;br /&gt;&lt;br /&gt;Ralf Hinze and Ross Paterson published &lt;a href="http://www.soi.city.ac.uk/%7Eross/papers/FingerTree.html"&gt;"Finger trees: a simple general-purpose data structure"&lt;/a&gt; in the &lt;i&gt;Journal of Functional Programming&lt;/i&gt; in 2006, and since then it has become relatively famous in functional programming circles as, as someone put it, "a data structure in a can". Finger trees combine several features that make them incredibly useful, including&lt;br /&gt;&lt;ul&gt;&lt;li&gt;purity; finger trees are a purely functional data structure,&lt;/li&gt;&lt;li&gt;flexibility; finger trees can be used as the basis for a host of more specialized data structures,&lt;/li&gt;&lt;li&gt;efficiency; finger trees provide efficient implementations of a number of operations, and&lt;/li&gt;&lt;li&gt;simplicity; like most extra fancy data structures, finger trees are more tedious than complex, and their relatively simple structure even reduces the complexity.&lt;/li&gt;&lt;/ul&gt;Until now, however, I have not seen any implementations in Java. Let's see what we can do about that.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;But first...&lt;/h2&gt;&lt;br /&gt;I want to make a quick digression about &lt;a href="http://en.wikipedia.org/wiki/Purely_functional"&gt;purely functional data structures&lt;/a&gt;. A purely functional data structure is one which does not provide nor make use of modification operations. The most common example of a purely functional data structure is a singly-linked list, as seen in Lisp and other functional languages. These structures have a number of advantages over traditional data structures: they are "persistent", in the sense that an update to the structure creates a new structure, leaving the original unchanged; and they are almost automatically thread safe. However, they have had problems achieving the performance of traditional structures. For example, while a non-functional hash table can provide best-case O(1) lookups, a search tree cannot normally provide better than O(log n) lookups.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;2-3 trees&lt;/h2&gt;&lt;br /&gt;Several of the discussions about finger trees such as &lt;a href="http://apfelmus.nfshost.com/articles/monoid-fingertree.html"&gt;apfelmus'&lt;/a&gt; and &lt;a href="http://scienceblogs.com/goodmath/2009/05/finally_finger_trees.php"&gt;Good Math, Bad Math's&lt;/a&gt; have focused on the interaction of monoids with tree structures; that is certainly where finger trees get much of their flexibility, but I think missing the first half of the solution Hinze and Paterson present is a significant loss. For one thing, bare finger trees by themselves support efficient, amortized O(1) deque operations (accessing the first and last elements) as well as O(log n) sequence concatenation.&lt;br /&gt;&lt;br /&gt;Finger trees, as originally described, are based on a form of search tree called a 2-3 tree. 2-3 trees are a little-known (to me, at least) variant designed for simplicity in keeping trees balanced. A 2-3 tree consists of&lt;br /&gt;&lt;ul&gt;&lt;li&gt;an empty tree,&lt;/li&gt;&lt;li&gt;a tree with a single value&lt;/li&gt;&lt;li&gt;a tree made of nodes, each of which has either two or three values and two or three child links.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Part of Hinze and Paterson's improvement involves modifying the base 2-3 tree to provide "fingers" akin to &lt;a href="http://en.wikipedia.org/wiki/Zipper_%28data_structure%29"&gt;Gérard Huet's zippers&lt;/a&gt;. These fingers provide efficient access to one to four elements on either end of the structure, while the remainder of the tree creates a "spine" down the center of the structure. As an end result, a finger tree consists of two collections of 1 to 4 elements, the first and last few elements of the collection, and a central spine made of a tree of 2-3 tree nodes of elements.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Digits&lt;/h2&gt;&lt;br /&gt;In this implementation, the "fingers" are instances of Digit (there is a pun there somewhere, but I am not sure I understand it). A Digit is a non-empty sequence of one to four elements. My original implementation used separate subclasses for the four possibilities, but that seemed excessively verbose.&lt;br /&gt;&lt;pre&gt;public class Digit&amp;lt;T&amp;gt; implements Iterable&amp;lt;T&amp;gt; {&lt;br /&gt;  private final int length;&lt;br /&gt;  private final List&amp;lt;T&amp;gt; contents;&lt;br /&gt;&lt;/pre&gt;Instead, I have implemented the Digits using a list in order to share the implementation. (I used the alternate approach on the Nodes below.)&lt;br /&gt;&lt;br /&gt;Methods like length(), isEmpty(), and get() are straightforward.&lt;br /&gt;&lt;pre&gt;public int length() { return length; }&lt;br /&gt;  public boolean isEmpty() { return length == 0; }&lt;br /&gt;  public T get(int index) { return this.contents.get(index); }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;On the other hand, because a Digit is necessarily a functional data structure, head()[2]&lt;a href="http://www.blogger.com/post-edit.g?blogID=5087326709910512917&amp;amp;postID=7182364149692632927#fn2"&gt;&lt;/a&gt; (which returns a Digit containing all but the last element of this Digit) may seem a little strange.&lt;br /&gt;&lt;pre&gt;public Digit&amp;lt;T&amp;gt; head() { return new Digit&amp;lt;T&amp;gt;(this.contents.subList(0, this.length - 1)); }&lt;br /&gt;&lt;/pre&gt;This method creates and returns a new digit instance containing the first length-1 elements of this Digit; the method tail() is symmetrical. These methods as written may not preserve the invariant of Digit, that there is at least one element.&lt;br /&gt;&lt;br /&gt;Likewise, append() and prepend return new Digits. The constructors &lt;i&gt;do&lt;/i&gt; ensure that the length invariant is established.&lt;br /&gt;&lt;pre&gt;public Digit&amp;lt;T&amp;gt; append(T t) { return new Digit&amp;lt;T&amp;gt;(this.contents, t); }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I also implemented a small number of collect() static methods to create Digits from zero to four elements.&lt;br /&gt;&lt;pre&gt;public static &amp;lt;T&amp;gt; Digit&amp;lt;T&amp;gt; collect(T t1, T t2) { return new Digit&amp;lt;T&amp;gt;(Arrays.asList(t1,t2)); }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The remainder of the Digit class consists of the Iterable&amp;lt;T&amp;gt; implementation and assorted constructors.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Nodes&lt;/h2&gt;&lt;br /&gt;The Node class is the implementation of the 2-3 tree internal nodes; for reasons that probably made sense at the time, I wrote the 2-nodes and 3-nodes as separate subclasses of a general Node class.&lt;br /&gt;&lt;pre&gt;public abstract class Node&amp;lt;T&amp;gt; {&lt;br /&gt;  public abstract Digit&amp;lt;T&amp;gt; toDigit();&lt;br /&gt;&lt;/pre&gt;Fortunately, the only method converts a Node to a Digit with the same elements.&lt;br /&gt;&lt;br /&gt;Two static methods provide easy constructors for Node2s and Node3s. (These serve the same function as Digit's collect(), which originally worked the same way.&lt;br /&gt;&lt;pre&gt;public static &amp;lt;T&amp;gt; Node&amp;lt;T&amp;gt; two(T x, T y) { return new Node2&amp;lt;T&amp;gt;(x,y); }&lt;br /&gt;  public static &amp;lt;T&amp;gt; Node&amp;lt;T&amp;gt; three(T x, T y, T z) { return new Node3&amp;lt;T&amp;gt;(x,y,z); }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The Node2 and Node3 classes are about as simple as possible.&lt;br /&gt;&lt;pre&gt;private static class Node2&amp;lt;T&amp;gt; extends Node&amp;lt;T&amp;gt;&lt;br /&gt;  {&lt;br /&gt;    public final T x, y;&lt;br /&gt;&lt;br /&gt;    public Node2(T x, T y)&lt;br /&gt;    {&lt;br /&gt;      this.x = x;&lt;br /&gt;      this.y = y;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override public Digit&amp;lt;T&amp;gt; toDigit() { return Digit.collect(x, y); }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Finger tree&lt;/h2&gt;&lt;br /&gt;The base finger tree provides efficient implementations of the deque operations: accessing, adding, and removing elements from each end of a sequence. It adds implementations of sequence concatination. The interface is below.&lt;br /&gt;&lt;pre&gt;public abstract class FingerTree&amp;lt;T&amp;gt;&lt;br /&gt;{&lt;br /&gt;  public abstract boolean isEmpty();&lt;br /&gt;&lt;br /&gt;  public abstract FingerTree&amp;lt;T&amp;gt; push(T t);  &lt;br /&gt;  public abstract FingerTree&amp;lt;T&amp;gt; pop();&lt;br /&gt;  public abstract T top();&lt;br /&gt;  &lt;br /&gt;  public abstract FingerTree&amp;lt;T&amp;gt; unshift(T t);&lt;br /&gt;  public abstract FingerTree&amp;lt;T&amp;gt; shift();&lt;br /&gt;  public abstract T bot();&lt;br /&gt;&lt;br /&gt;  public abstract FingerTree&amp;lt;T&amp;gt; append(FingerTree&amp;lt;T&amp;gt; other);&lt;br /&gt;  public abstract FingerTree&amp;lt;T&amp;gt; prepend(FingerTree&amp;lt;T&amp;gt; other);&lt;br /&gt;&lt;/pre&gt;Notice that the deque operations come in trios: push() adds an element and pop() removes an element with both returning a new, modified FingerTree, and top() returns the last element in the sequence without changing the sequence. (Keep in mind I am misusing the words "add", "remove", and "modified"; the original FingerTree is still available and the new, returned tree shares as much of the structure of the original as possible.)&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Empty&lt;/h3&gt;&lt;br /&gt;The FingerTree is implemented as three classes, Empty representing an empty tree, Single representing a tree containing one element, and Deep representing a tree containing more than one element. The Empty and Single classes are very simple; Empty is below.&lt;br /&gt;&lt;pre&gt;public static class Empty&amp;lt;T&amp;gt; extends FingerTree&amp;lt;T&amp;gt;&lt;br /&gt;  {&lt;br /&gt;    @Override public boolean isEmpty() { return true; }&lt;br /&gt;&lt;br /&gt;    @Override public Single&amp;lt;T&amp;gt; push(T t) { return new Single&amp;lt;T&amp;gt;(t); }&lt;br /&gt;    @Override public FingerTree&amp;lt;T&amp;gt; pop() { throw new IllegalStateException(); }&lt;br /&gt;    @Override public T top() { throw new IllegalStateException(); }&lt;br /&gt;    // ...&lt;br /&gt;    @Override public FingerTree&amp;lt;T&amp;gt; append(FingerTree&amp;lt;T&amp;gt; other) { return other; }&lt;br /&gt;    @Override public FingerTree&amp;lt;T&amp;gt; prepend(FingerTree&amp;lt;T&amp;gt; other) { return other; }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;The implementations of shift(), unshift(), and bot() are identical to push(), pop(), and top().&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Single&lt;/h3&gt;&lt;br /&gt;Single is very nearly as simple.&lt;br /&gt;&lt;pre&gt;public static class Single&amp;lt;T&amp;gt; extends FingerTree&amp;lt;T&amp;gt;&lt;br /&gt;  {&lt;br /&gt;    public final T t;&lt;br /&gt;&lt;br /&gt;    public Single(T t) { this.t = t; }&lt;br /&gt;&lt;br /&gt;    @Override public boolean isEmpty() { return false; }&lt;br /&gt;&lt;br /&gt;    @Override public FingerTree&amp;lt;T&amp;gt; push(T n)&lt;br /&gt;      { return new Deep&amp;lt;T&amp;gt;(Digit.collect(t), new Empty&amp;lt;Node&amp;lt;T&amp;gt;&amp;gt;(), Digit.collect(n)); }&lt;br /&gt;&lt;br /&gt;    @Override public T top() { return t;  }&lt;br /&gt;&lt;br /&gt;    @Override public FingerTree&amp;lt;T&amp;gt; pop() { return new Empty&amp;lt;T&amp;gt;(); }&lt;br /&gt;    // ...&lt;br /&gt;    @Override public FingerTree&amp;lt;T&amp;gt; append(FingerTree&amp;lt;T&amp;gt; other) { return other.unshift(t); }&lt;br /&gt;    @Override public FingerTree&amp;lt;T&amp;gt; prepend(FingerTree&amp;lt;T&amp;gt; other) { return other.push(t); }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;The important method is push() (and unshift()), which introduce Deep, the class which implements the trio of left and right Digits and central FingerTree spine. The important detail is that, while the new Deep object is a collection of T, the spine FingerTree is a collection of Node&amp;lt;T&amp;gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Deep&lt;/h3&gt;&lt;br /&gt;Deep is indeed the magic ingredient of the FingerTree. As expected, it consists of left and right Digit&amp;lt;T&amp;gt; and a centeral FingerTree&amp;lt;Node&amp;lt;T&amp;gt;&amp;gt; spine.&lt;br /&gt;&lt;pre&gt;public static class Deep&amp;lt;T&amp;gt; extends FingerTree&amp;lt;T&amp;gt;&lt;br /&gt;  {&lt;br /&gt;    public final Digit&amp;lt;T&amp;gt; left;&lt;br /&gt;    public final FingerTree&amp;lt;Node&amp;lt;T&amp;gt;&amp;gt; spine;&lt;br /&gt;    public final Digit&amp;lt;T&amp;gt; right;&lt;br /&gt;&lt;br /&gt;    public Deep(Digit&amp;lt;T&amp;gt; l, FingerTree&amp;lt;Node&amp;lt;T&amp;gt;&amp;gt; s, Digit&amp;lt;T&amp;gt; r)&lt;br /&gt;    {&lt;br /&gt;      this.left = l;&lt;br /&gt;      this.spine = s;&lt;br /&gt;      this.right = r;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override public boolean isEmpty() { return false; }&lt;br /&gt;&lt;br /&gt;    @Override public T top() { return right.get(right.length() - 1); }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public FingerTree&amp;lt;T&amp;gt; push(T t)&lt;br /&gt;    {&lt;br /&gt;      if (right.length() &amp;lt; 4)&lt;br /&gt;      {&lt;br /&gt;        return new Deep&amp;lt;T&amp;gt;(left, spine, right.append(t));&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;        Node&amp;lt;T&amp;gt; node = Node.three(right.get(0), right.get(1), right.get(2));&lt;br /&gt;        return new Deep&amp;lt;T&amp;gt;(left, spine.push(node), Digit.collect(right.get(3), t));&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;In the push() method, if the current length of the right Digit is less than four, the new element t can be handled by adding it to the Digit. If the right Digit is already full, it must be broken into the first three elements, which are placed in a Node&amp;lt;T&amp;gt; and pushed onto the spine, and the fourth and new elements, which become the contents of the new right Digit.&lt;br /&gt;&lt;br /&gt;push() demonstrates one of the principles that makes FingerTrees efficient. Adding a new element to a FingerTree is O(1) 2/3 of the time, when the new element fits in the terminal Digit; it only needs to recurse 1/3 of the time. As a result, &lt;i&gt;amortized&lt;/i&gt; over a number of operations, the push() (and the other deque operations) are O(1). Hinze and Paterson say,&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Each deque operation may recurse down the spine of the finger tree, and thus take Θ(log n) time in the worst case. However, it can be shown that these operations take only Θ(1) amortized time, even in a persistent setting. The analysis is essentially the same as Okasaki’s for implicit deques (Okasaki, 1998). We outline the main points here.&lt;br /&gt;&lt;br /&gt;We classify digits of two or three elements (which are isomorphic to elements of type [Node&amp;lt;T&amp;gt;]) as safe, and those of one or four elements as dangerous. A deque operation may only propagate to the next level from a dangerous digit, but in doing so it makes that digit safe, so that the next operation to reach that digit will not propagate. Thus, at most half of the operations descend one level, at most a quarter two levels, and so on. Consequently, in a sequence of operations, the average cost is constant.&lt;/blockquote&gt;&lt;br /&gt;In other words, while any specific operations may require O(log n) operations, a large number of sequential operations will behave appear to be O(1).&lt;br /&gt;&lt;br /&gt;The pop() method is longer, but not any more difficult. It has three cases:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If the right Digit has more than one element, the new FingerTree can be built by dropping the rightmost element.&lt;/li&gt;&lt;li&gt;If the right Digit has only one element, that element can be dropped and a new FingerTree constructed by pulling the rightmost Node from the spine and unpacking it into the right Digit.&lt;/li&gt;&lt;li&gt;If the right Digit has only one element and the spine is empty, then pop() must redistribute elements from the left Digit, potentially making the new FingerTree an instance of Single.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;@Override&lt;br /&gt;    public FingerTree&amp;lt;T&amp;gt; pop()&lt;br /&gt;    {&lt;br /&gt;      if (right.length() &amp;gt; 1)&lt;br /&gt;      {&lt;br /&gt;        return new Deep&amp;lt;T&amp;gt;(left, spine, right.head());&lt;br /&gt;      }&lt;br /&gt;      else if (!spine.isEmpty())&lt;br /&gt;      {&lt;br /&gt;        return new Deep&amp;lt;T&amp;gt;(left, spine.pop(), spine.top().toDigit());&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;        switch (left.length())&lt;br /&gt;        {&lt;br /&gt;        case 1:&lt;br /&gt;          return new Single&amp;lt;T&amp;gt;(left.get(0));&lt;br /&gt;        case 2:&lt;br /&gt;          return new Deep&amp;lt;T&amp;gt;(Digit.collect(left.get(0)),&lt;br /&gt;                                spine,&lt;br /&gt;                                Digit.collect(left.get(1)));&lt;br /&gt;        case 3:&lt;br /&gt;          return new Deep&amp;lt;T&amp;gt;(Digit.collect(left.get(0)),&lt;br /&gt;                                spine,&lt;br /&gt;                                Digit.collect(left.get(1), left.get(2)));&lt;br /&gt;        case 4:&lt;br /&gt;          return new Deep&amp;lt;T&amp;gt;(Digit.collect(left.get(0), left.get(1)),&lt;br /&gt;                                spine,&lt;br /&gt;                                Digit.collect(left.get(2), left.get(3)));&lt;br /&gt;        default:&lt;br /&gt;          throw new IllegalStateException();&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;The analysis of pop() is similar to that of push().&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Concatenation&lt;/h3&gt;&lt;br /&gt;In addition to the deque operations, Deep implements sequence concatenation in the form of append() and prepend() (which is symmetric with append()). &lt;br /&gt;&lt;pre&gt;@Override&lt;br /&gt;    public FingerTree&amp;lt;T&amp;gt; append(FingerTree&amp;lt;T&amp;gt; other)&lt;br /&gt;    {&lt;br /&gt;      if (! (other instanceof Deep&amp;lt;?&amp;gt;))&lt;br /&gt;      {&lt;br /&gt;        return other.prepend(this);&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;        Deep&amp;lt;T&amp;gt; o = (Deep&amp;lt;T&amp;gt;) other;&lt;br /&gt;        return new Deep&amp;lt;T&amp;gt;(left, foldWings(this, o), o.right);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;In the new FingerTree, the left Digit is the left digit of the appended-to tree, the right Digit is the right digit of of the appended tree, and the spine is built from the remaining two digits and the spines by the foldWings() method.&lt;br /&gt;&lt;br /&gt;The foldWings() method first collects all of the elements from the two inner Digits and, arbitrarily choosing the left spine, pushes them into the spine. This process is the task of the while loop in foldWings() and is complicated by the need to break the two to eight elements into Nodes of two or three elements. This code prefers three-element Nodes, and only uses two-element Nodes when either only two elements are left or four elements are left, in which case two two-element Nodes are needed. Finally, the new spine is created and returned, by recursively appending the new left and original right spines.&lt;br /&gt;&lt;pre&gt;private static &amp;lt;T&amp;gt; FingerTree&amp;lt;Node&amp;lt;T&amp;gt;&amp;gt; foldWings(Deep&amp;lt;T&amp;gt; port, Deep&amp;lt;T&amp;gt; starboard)&lt;br /&gt;    {&lt;br /&gt;      List&amp;lt;T&amp;gt; fist = new ArrayList&amp;lt;T&amp;gt;(port.right.length() + starboard.left.length());&lt;br /&gt;      for (T t : port.right) { fist.add(t); }&lt;br /&gt;      for (T t : starboard.left) { fist.add(t); }&lt;br /&gt;      int seen = 0;&lt;br /&gt;      int all = fist.size();  /* 2 &amp;lt;= all &amp;lt;= 8 */&lt;br /&gt;      FingerTree&amp;lt;Node&amp;lt;T&amp;gt;&amp;gt; spine = port.spine;&lt;br /&gt;      while (seen &amp;lt; all)&lt;br /&gt;      {&lt;br /&gt;        int diff = all - seen;  /* Initially, 2 &amp;lt;= diff &amp;lt;= 8 */&lt;br /&gt;        if (diff == 2)&lt;br /&gt;        {&lt;br /&gt;          T a = fist.get(seen++);&lt;br /&gt;          T b = fist.get(seen++);&lt;br /&gt;          spine = spine.push(Node.two(a,b));&lt;br /&gt;          /* diff reduced by 2 */&lt;br /&gt;        }&lt;br /&gt;        else if (diff == 4)&lt;br /&gt;        {&lt;br /&gt;          T a = fist.get(seen++);&lt;br /&gt;          T b = fist.get(seen++);&lt;br /&gt;          T c = fist.get(seen++);&lt;br /&gt;          T d = fist.get(seen++);&lt;br /&gt;          spine = spine.push(Node.two(a,b)).push(Node.two(c, d));&lt;br /&gt;          /* diff reduced by 4 */&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;          T a = fist.get(seen++);&lt;br /&gt;          T b = fist.get(seen++);&lt;br /&gt;          T c = fist.get(seen++);&lt;br /&gt;          spine = spine.push(Node.three(a,b,c));&lt;br /&gt;          /* diff reduced by 3 */&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      /*    (port.spine)&lt;br /&gt;         + ("loose" port-right nodes, folded)&lt;br /&gt;         + ("loose" starboard-left nodes, folded)&lt;br /&gt;         + (starboard.spine) */&lt;br /&gt;      return spine.append(starboard.spine);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;The analysis of concatenation by Hinze and Paterson is,&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;It is easy to check that in each of the invocations of [append, the list fist has length at most 8], so each of these invocations takes Θ(1) time. The recursion terminates when we reach the bottom of the shallower tree, with up to 4 insertions, so the total time taken is Θ(log(min{n1 , n2 })), where n1 and n2 are the numbers of elements in the argument trees. &lt;br /&gt;&lt;br /&gt;Note that the debit analysis of Section 3.2 remains valid, because although [append] must discharge any debits on the nodes on the spines that are merged, there will be at most Θ(log(min{n1 , n2 })) of these.&lt;/blockquote&gt;&lt;br /&gt;&lt;h2&gt;Comparisons&lt;/h2&gt;&lt;br /&gt;Given the analysis of the behavior of finger trees as sequences, how do they actually perform? I ran some quick tests, comparing them with JDK-standard ArrayLists and LinkedLists on element addition, removal, and concatenation. The contents of the sequences were Integers.&lt;br /&gt;&lt;br /&gt;Keep in mind that these results are &lt;i&gt;benchmarks&lt;/i&gt; (at the lower level of lies, damned lies, statistics, and benchmarks), and are also poorly done benchmarks. I did not use a quiescent machine, I did not "warm up" the program, I did not make any effort to optimize anything, I even ran the things in Eclipse for crying out loud. As a result, they are full of noise, they are not statistically significant (although they were repeatable), and I would not hesitate to disclaim them if someone really wants to complain. But they are kind of interesting.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Push&lt;/h3&gt;&lt;br /&gt;For inserting elements, I started with a sequence of n elements and timed adding n elements, reporting the time taken divided by n. The additions were performed by&lt;br /&gt;&lt;pre&gt;t = t.push(j);         /* FingerTree */&lt;br /&gt;al.add(j);             /* ArrayList */&lt;br /&gt;ll.add(j);             /* LinkedList */&lt;br /&gt;&lt;/pre&gt;The results are shown in Figure 1.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: thin solid black; margin: 1em; padding: 1em;"&gt;&lt;img alt="graph of FingerTree vs ArrayList and LinkedList performance for element addition" height="360" src="http://www.crsr.net/images/fingertree-push.png" width="480" /&gt;&lt;br /&gt;&lt;b&gt;Figure 1: Adding an element&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;Yes, the left side of the graph is &lt;i&gt;very&lt;/i&gt; inaccurate. Sorry.&lt;br /&gt;&lt;br /&gt;I added some guide lines showing log n, n, and \(n^2\) performance. I also used log scales for both horizontal and vertical axes, which I &lt;i&gt;really&lt;/i&gt; wish more systems researchers used in papers, since otherwise the right half of the graph would be effectively empty.&lt;br /&gt;&lt;br /&gt;The primary thing to notice is that the trends of the three lines are roughly the same, and indicate something like O(1) performance, which all three should exhibit.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Pop&lt;/h3&gt;&lt;br /&gt;For removing elements, I followed a similar process, starting with a sequence of n elements, inserting n more elements and then timing removing those n elements with the following operations:&lt;br /&gt;&lt;pre&gt;t = t.pop();                /* FingerTree */&lt;br /&gt;al.remove(al.size() - 1);   /* ArrayList */&lt;br /&gt;ll.remove(ll.size() - 1);   /* LinkedList */&lt;br /&gt;&lt;/pre&gt;The results are shown in Figure 2.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: thin solid black; margin: 1em; padding: 1em;"&gt;&lt;img alt="graph of FingerTree vs ArrayList and LinkedList performance for element removal" height="360" src="http://www.crsr.net/images/fingertree-pop.png" width="480" /&gt;&lt;br /&gt;&lt;b&gt;Figure 2: Removing an element&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Concatenation&lt;/h3&gt;&lt;br /&gt;Comparing concatenation, I concatenated two sequences of n elements 100 times (resulting in some truly huge sequences), reporting the total time. The operations were:&lt;br /&gt;&lt;pre&gt;t = t.append(t2);       /* FingerTree */&lt;br /&gt;al.addAll(al2);         /* ArrayList */&lt;br /&gt;ll.addAll(ll2);         /* LinkedList */&lt;br /&gt;&lt;/pre&gt;The results are shown in Figure 3.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: thin solid black; margin: 1em; padding: 1em;"&gt;&lt;img alt="graph of FingerTree vs ArrayList and LinkedList performance for concatenation" height="360" src="http://www.crsr.net/images/fingertree-append.png" width="480" /&gt;&lt;br /&gt;&lt;b&gt;Figure 3: Concatenating sequences&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;Figure 3 shows the one advantage of finger trees: the slope of the finger tree concatenation line is significantly less than that of the ArrayList or LinkedList; FingerTree looks, in fact, to be roughly log n, while the other two are roughly parallel to n.&lt;br /&gt;&lt;br /&gt;With some luck, I will be following this post with another that tells the rest of the finger tree story.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;1.&lt;a href="http://www.blogger.com/post-edit.g?blogID=5087326709910512917&amp;amp;postID=7182364149692632927" name="fn1"&gt;&lt;/a&gt; Cue Petey Fisk.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. Think the head and tail Unix commands.&lt;br /&gt;&lt;br /&gt;[Edit: fixed Ralf Hinze's and Ross Paterson's names. Darn you, traitorous fingers! Darn you!]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-7182364149692632927?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/7182364149692632927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=7182364149692632927' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7182364149692632927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7182364149692632927'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2010/11/finger-trees.html' title='Finger Trees'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-563336238811817831</id><published>2010-11-23T13:27:00.000-06:00</published><updated>2010-11-23T13:27:32.676-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='http'/><category scheme='http://www.blogger.com/atom/ns#' term='quote'/><category scheme='http://www.blogger.com/atom/ns#' term='vmware'/><title type='text'>Quote o' the Day: Cloudebauchery</title><content type='html'>&lt;a href="http://www.shitmycloudevangelistsays.com/blog/?p=39"&gt;Two Clouds walk into a bar. Bartender says “Your server will be right with you”.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-563336238811817831?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/563336238811817831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=563336238811817831' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/563336238811817831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/563336238811817831'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2010/11/quote-o-day-cloudebauchery.html' title='Quote o&apos; the Day: Cloudebauchery'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-4564478567989045438</id><published>2010-11-11T20:03:00.001-06:00</published><updated>2011-11-10T16:27:18.842-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='toy problems'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='notation'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='Dijkstra'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><title type='text'>Knights, knaves, and Program Construction</title><content type='html'>&lt;span style="float:right;margin:10px;"&gt;&lt;a href="http://www.amazon.com/gp/product/0470848820/ref=as_li_tf_il?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0470848820"&gt;&lt;img border="0" src="http://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL160_&amp;ASIN=0470848820&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=wwwcrsrnet-20&amp;ServiceVersion=20070822" &gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0470848820&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/span&gt;I have a confession to make: I was raised in the &lt;a href="http://www.cs.utexas.edu/"&gt;land of Dijkstra&lt;/a&gt;. Although I have posted frequently about exploring Haskell and other functional languages, the lambda calculus is comparatively new to me. Denotational semantics, category theory, generalized algebraic data types, these are all foreign from the approach I first learned: what I learned to call &lt;a href="http://en.wikipedia.org/wiki/Axiomatic_semantics"&gt;axiomatic semantics&lt;/a&gt;. So, when I finally dragged out a copy of &lt;a href="http://www.cs.nott.ac.uk/%7Ercb/"&gt;Roland Backhouse&lt;/a&gt;'s &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0470848820/ref=as_li_tf_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399373&amp;creativeASIN=0470848820"&gt;Program Construction: Calculating Implementations from Specifications&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0470848820&amp;camp=217145&amp;creative=399373" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt; and started reading (I am currently up to chapter five), I was brought back to the long-lost days of my youth, days of Phil. 313k, CS 336, &lt;a href="http://www.cs.utexas.edu/users/ham/richards/"&gt;Ham Richards&lt;/a&gt;, &lt;a href="http://www.amazon.ca/Science-Programming-David-Gries/dp/0387964800/ref=sr_1_5?s=books&amp;amp;ie=UTF8&amp;amp;qid=1289518805&amp;amp;sr=1-5"&gt;David Gries&lt;/a&gt;, ....&lt;br /&gt;&lt;br /&gt;Anyway, chapter five is on calculational logic, using the properties of equality and negation to &lt;i&gt;calculate&lt;/i&gt; the logical consequences of propositions. What I found especially entertaining is Backhouse's use of examples from &lt;a href="http://en.wikipedia.org/wiki/Raymond_Smullyan#Logic_puzzles"&gt;Raymond Smullyan's knights and knaves puzzles&lt;/a&gt; to illustrate the principles. The cool part is that so many of the puzzles are so easy to solve using so simple a box of tools: negation, equality, and the properties of equality, transitivity, symmetry, and associativity.&lt;br /&gt;&lt;br /&gt;&lt;span style="float:left;margin:10px;"&gt;&lt;a href="http://www.amazon.com/gp/product/0192801422/ref=as_li_tf_il?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0192801422"&gt;&lt;img border="0" src="http://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL160_&amp;ASIN=0192801422&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=wwwcrsrnet-20&amp;ServiceVersion=20070822" &gt;&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0192801422&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/span&gt;&lt;h2&gt;For example&lt;/h2&gt;&lt;br /&gt;Briefly, these puzzles involve you as a traveler on an island inhabited only by knights, who only tell the truth, and knaves, who only tell lies. Consider the following question from &lt;i&gt;&lt;a href="http://www.amazon.com/gp/product/0192801422/ref=as_li_tf_tl?ie=UTF8&amp;tag=wwwcrsrnet-20&amp;linkCode=as2&amp;camp=217145&amp;creative=399369&amp;creativeASIN=0192801422"&gt;To Mock a Mockingbird&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=wwwcrsrnet-20&amp;l=as2&amp;o=1&amp;a=0192801422&amp;camp=217145&amp;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;&lt;/i&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;Question 1&lt;/i&gt;: Is it possible for any inhabitant of this island to claim that he is a knave?&lt;/blockquote&gt;&lt;br /&gt;Backhouse points out, "Smullyan's proofs invariably involve detailed case analysis." Case analysis is a very useful technique (in both logic and programming), but it quickly becomes complex and tedious, making it a less preferred alternative. Instead, Backhouse proposes something like the following approach (the example here is mine; don't blame Backhouse):&lt;br /&gt;\[&lt;br /&gt;\begin{equation}\begin{split}&lt;br /&gt;&amp;amp; A \equiv \neg A &amp;amp; \\&lt;br /&gt;\equiv &amp;amp;                 &amp;amp; \{ \textrm{Def. negation} \}\\&lt;br /&gt;&amp;amp; A \equiv A \equiv \textbf{false} \\&lt;br /&gt;\equiv &amp;amp;                 &amp;amp; \{ \textrm{Assoc., def. const. true} \}\\&lt;br /&gt;&amp;amp; \textbf{true} \equiv \textbf{false} \\&lt;br /&gt;\equiv &amp;amp;                 &amp;amp; \{ \textrm{Simpl.} \}\\&lt;br /&gt;&amp;amp; \textbf{false}&lt;br /&gt;\end{split}\end{equation}&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;The initial formalization of the question begins with a native, named A; the logical proposition \(A\) indicates, "A is a knight", and the formalization of any statement by A begins, \(A \equiv \ldots\) because the entire statement will be true if and only if A is a knight. Therefore, the original equation can be read, "A is a knight if and only if A is a knave" or as "The statement 'A is a knave' is true if and only if A is a knight." The final statement, \(\textbf{false}\), indicates that no inhabitant of this island can claim he is a knave. In Smullyan's reasoning, that statement would be a lie for a knight and the truth for a knave.&lt;br /&gt;&lt;br /&gt;(There are a small stack of identical operations here: equality \(=\), equivalence \(\equiv\), and bi-implication \(\leftrightarrow\) (a.k.a. "if and only if", or just "iff"). The first two directly indicate the same thing, that the thing on the left is the same as the thing on the right, but are kept separate because equality applies to any two things: 4, true, a puppy,..., while equivalence is limited to boolean values. This prevents confusion in statements like \(4 = 4 = \textbf{true}\), which would mean something completely different parenthesized like \(4 = (4 = \textbf{true})\). "Iff" simply has the same logical meaning as equivalence, but sometimes reads easier.)&lt;br /&gt;&lt;br /&gt;Here is another example:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;Question 4:&lt;/i&gt; [Suppose an inhabitant A says about himself and his brother B]: "Exactly one of us is a knave." What type is A and what type is B?&lt;/blockquote&gt;&lt;br /&gt;I would formalize the calculation as:&lt;br /&gt;\[&lt;br /&gt;\begin{equation}\begin{split}&lt;br /&gt;&amp;amp; A \equiv A \not\equiv B &amp;amp; \\&lt;br /&gt;\equiv &amp;amp;                          &amp;amp; \{ \textrm{Def. not equiv.} \}\\&lt;br /&gt;&amp;amp; A \equiv A \equiv \neg B &amp;amp; \\&lt;br /&gt;\equiv &amp;amp;                          &amp;amp; \{ \textrm{Def. negation} \}\\&lt;br /&gt;&amp;amp; A \equiv A \equiv B \equiv \textbf{false} &amp;amp; \\&lt;br /&gt;\equiv &amp;amp;                          &amp;amp; \{ \textrm{Def. const. true} \}\\&lt;br /&gt;&amp;amp; \textbf{true} \equiv B \equiv \textbf{false} &amp;amp; \\&lt;br /&gt;\equiv &amp;amp;                          &amp;amp; \{ \textrm{Assoc., simpl.} \}\\&lt;br /&gt;&amp;amp; B \equiv \textbf{false} &amp;amp; \\&lt;br /&gt;\equiv &amp;amp;                          &amp;amp; \{ \textrm{Def. negation} \}\\&lt;br /&gt;&amp;amp; \neg B &amp;amp;&lt;br /&gt;\end{split}\end{equation}&lt;br /&gt;\]&lt;br /&gt;&lt;br /&gt;The answer to the question is that B is a knave, but the statement gives no information about A.&lt;br /&gt;&lt;br /&gt;The astute reader will notice that I skipped a few questions there. I had to because, after a good bit of thought I have no idea how to formalize "...to claim that he and his brother are both knaves" or "at least one of us is a knave" using only equivalence and negation. On the other hand, they can easily be formalized using conjunction and disjunction. I propose the following reason for my difficulties: it is impossible to express all logical propositions using equivalence and negation. In particular, it is not possible to express the proposition \(p \wedge q\).&lt;br /&gt;&lt;br /&gt;Define a &lt;i&gt;symmetric&lt;/i&gt; proposition to be one where the truth table for the proposition has an even number of &lt;b&gt;true&lt;/b&gt; values, where the truth table has one row for each possible combination of truth assignments to the variables of the proposition. Define a &lt;i&gt;asymmetric&lt;/i&gt; proposition to be one with an odd number of &lt;b&gt;true&lt;/b&gt; values.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;\(p\) (a single variable) is symmetric. Trust me: true or false.&lt;/li&gt;&lt;li&gt;&lt;b&gt;true&lt;/b&gt; and &lt;b&gt;false&lt;/b&gt; are symmetric. They have no variables and so no rows in their truth tables.&lt;/li&gt;&lt;li&gt;\(p \equiv q\) is symmetric. It is true when both are true or when both are false.&lt;/li&gt;&lt;li&gt;\(\neg p\) is symmetric. True is false and false is true.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;However, \(p \wedge q\) is asymmetric; it is only true in the one case where both \(p\) and \(q\) are true. An asymmetric proposition cannot be built with only symmetric components. (This argument could be formalized by induction on the structure of propositions.)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;This matters...why?&lt;/h2&gt;&lt;br /&gt;This stuff, besides being an opportunity to play with &lt;a href="http://www.mathjax.org/"&gt;MathJax&lt;/a&gt;, is valuable for a number of reasons: On the one hand, programs are proofs. Quite beyond the &lt;a href="http://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence"&gt;Curry-Howard correspondence&lt;/a&gt;, programs and formal proofs have a great deal in common, including the amount of detail required and the advantages of abstraction. Further, and more specifically, axiomatic semantics are fundamentally how I &lt;i&gt;understand&lt;/i&gt; programs, particularly imperative programs in languages such as Java. (Axiomatic semantics are somewhat less useful in Haskell or Prolog, probably giving rise to the difficulties I have had with them over the years.)&lt;br /&gt;&lt;br /&gt;Further, the ability to reason closely is somewhat important to a programmer. When I started, I did not know that conjunction could not be expressed using equivalence and negation; given the proof sketch I gave above, I am still not sure. I would bet that someone &lt;i&gt;has&lt;/i&gt; proved it one way or another, but I am not familiar with that proof and could not easily find it. However, I have convinced myself, and have done so using basically the same techniques I used when I was fooling with a weird string fiddling problem in Java last weekend.&lt;br /&gt;&lt;br /&gt;Expect more faffing about with proofs soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-4564478567989045438?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/4564478567989045438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=4564478567989045438' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4564478567989045438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/4564478567989045438'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2010/11/knights-knaves-and-program-construction.html' title='Knights, knaves, and Program Construction'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-7795840533505213729</id><published>2010-11-03T17:08:00.001-05:00</published><updated>2010-11-04T13:13:37.907-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='notation'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>Subclassing and Java Generics, revisited</title><content type='html'>Last summer, I wrote a post working through the relationship between &lt;a href="http://maniagnosis.crsr.net/2010/07/subclassing-and-java-generics.html"&gt;subtyping and generics in Java&lt;/a&gt;. Unfortunately, I never really related my conclusions to Java as it is spoken in the wild. The topic came up again, and once again I not only could not remember the ideas, I couldn't even remember the words.&lt;br /&gt;&lt;br /&gt;Specifically, the problem started with an attempt to create a Map whose values were themselves Maps.&lt;br /&gt;&lt;pre&gt;Map&amp;lt;String, Map&amp;lt;String,String&gt;&gt; map = &lt;span style="color:red"&gt;new HashMap&amp;lt;String, HashMap&amp;lt;String,String&gt;&gt;()&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;(The red highlighted code will not compile and shows the cute little red underline in Eclipse.)&lt;br /&gt;&lt;br /&gt;The question became one of generics and subtyping with the following attempt to fix the error, which appears to work but just pushes the error down to the use of the map.&lt;br /&gt;&lt;pre&gt;Map&amp;lt;String, ? extends Map&amp;lt;String,String&gt;&gt; map = new HashMap&amp;lt;String, HashMap&amp;lt;String,String&gt;&gt;();&lt;br /&gt;map.&lt;span style="color:red"&gt;put("one", new HashMap&amp;lt;String, String&gt;())&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;The problem there, I think, is that the Java compiler believes the values of map to be some-anonymous-but-concrete subtype of Map&amp;lt;String,String&gt;, and sees the call to put() as an attempt to insert a HashMap&amp;lt;String,String&gt; into a position requiring some-anonymous-but-concrete subtype of Map&amp;lt;String,String&gt;, which does not match HashMap&amp;lt;String,String&gt;. Or something like that.&lt;br /&gt;&lt;br /&gt;The ultimate fix is to un-typo the HashMap constructor call in the original assignment to map, leaving the values of the map to be generic Map&amp;lt;String,String&gt;'s rather than specific HashMaps.&lt;br /&gt;&lt;pre&gt;Map&amp;lt;String, Map&amp;lt;String,String&gt;&gt; map = new HashMap&amp;lt;String, Map&amp;lt;String,String&gt;&gt;();&lt;br /&gt;map.put("one", new HashMap&amp;lt;String, String&gt;());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Class structure&lt;/h2&gt;&lt;br /&gt;Anyway, my purpose here is to recreate my table of what works and what does not using actual Java code rather than the pseudo-Java examples of my previous post. The class structure I need to work with is:&lt;br /&gt;&lt;pre&gt;public class A { }&lt;br /&gt;public class B extends A { }&lt;br /&gt;public class C extends A { }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To briefly recap my previous post, given those class definitions where B is a subtype of A (or, B &amp;lt;: A),&lt;br /&gt;&lt;ul&gt;&lt;li&gt;List&amp;lt;B&gt; can be used as a subtype of List&amp;lt;A&gt; (or List&amp;lt;B&gt; &amp;lt;: List&amp;lt;A&gt;), which is described as a &lt;b&gt;covariant&lt;/b&gt; use,&lt;/li&gt;&lt;li&gt;List&amp;lt;A&gt; can be used as a subtype of List&amp;lt;B&gt; (or List&amp;lt;A&gt; &amp;lt;: List&amp;lt;B&gt;), which is described as a &lt;b&gt;contravariant&lt;/b&gt; use, or&lt;/li&gt;&lt;li&gt;List&amp;lt;A&gt; and List&amp;lt;B&gt; can be entirely unrelated and cannot be interchanged, which is described as &lt;b&gt;invariant&lt;/b&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The two important variations are covariance and contravariance (in C++ with templates, as far as I know, generics are treated as invariant, which is entirely reasonable if somewhat less featuriferous).&lt;br /&gt;&lt;br /&gt;Whether covariance or contravariance works depends on how the subtype relationship is being used. Now, by "works" I mean "is &lt;i&gt;guaranteed&lt;/i&gt; not to result in runtime errors". Further, by "how the subtype relationship is being used", I mean "whether information is being &lt;i&gt;inserted&lt;/i&gt; or &lt;i&gt;extracted&lt;/i&gt; from the generic type".&lt;br /&gt;&lt;br /&gt;The following table shows the four possibilities, with resulting errors. (I have highlighted the extends/super keywords to show the relationship with covariance and contravariance.) Each quadrant of the table contains two methods. The first, top method has a generically typed, covariant- or contravariant-use parameter, which potentially shows a compile-time error. The second, bottom, method shows code that uses the top method to either insert or extract an element from a List.&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;th style="text-align:center"&gt;Covariant&lt;/th&gt;&lt;th style="text-align:center"&gt;Contravariant&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th style="text-align:right"&gt;Extraction&lt;/th&gt; &lt;td style="margin: 5px; border: thin solid black; padding: 5px;"&gt;&lt;pre&gt;public A covExtInner(List&amp;lt;? &lt;b&gt;extends&lt;/b&gt; A&gt; as) {&lt;br /&gt;    return as.get(0);&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public void covariantExtraction() {&lt;br /&gt;    List&amp;lt;B&gt; bs = new ArrayList&amp;lt;B&gt;();&lt;br /&gt;    bs.add(new B());&lt;br /&gt;    &lt;br /&gt;    A a = covExtInner(bs);&lt;br /&gt;  }&lt;/pre&gt;&lt;/td&gt;   &lt;td style="margin: 5px; border: thin solid black; padding: 5px;"&gt;&lt;pre&gt;public B conExtInner(List&amp;lt;? &lt;b&gt;super&lt;/b&gt; B&gt; bs) {&lt;br /&gt;    return &lt;span style="color:red"&gt;bs.get(0)&lt;/span&gt;;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public void contravariantExtraction() {&lt;br /&gt;    List&amp;lt;A&gt; as = new ArrayList&amp;lt;A&gt;();&lt;br /&gt;    as.add(new A());&lt;br /&gt;    &lt;br /&gt;    B b = conExtInner(as);&lt;br /&gt;  }&lt;/pre&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt;   &lt;th style="text-align:right"&gt;Insertion&lt;/th&gt;   &lt;td style="margin: 5px; border: thin solid black; padding: 5px;"&gt;&lt;pre&gt;public void covInsInner(List&amp;lt;? &lt;b&gt;extends&lt;/b&gt; A&gt; as, A a) {&lt;br /&gt;    as.&lt;span style="color:red"&gt;add(a)&lt;/span&gt;;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public void covariantInsertion() {&lt;br /&gt;    List&amp;lt;B&gt; bs = new ArrayList&amp;lt;B&gt;();&lt;br /&gt;    A a = new A();&lt;br /&gt;    &lt;br /&gt;    covInsInner(bs, a);&lt;br /&gt;  }&lt;/pre&gt;&lt;/td&gt;   &lt;td style="margin: 5px; border: thin solid black; padding: 5px;"&gt;&lt;pre&gt;public void conInsInner(List&amp;lt;? &lt;b&gt;super&lt;/b&gt; B&gt; bs, B b) {&lt;br /&gt;    bs.add(b);&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public void contravariantInsertion() {&lt;br /&gt;    List&amp;lt;A&gt; as = new ArrayList&amp;lt;A&gt;();&lt;br /&gt;    B b = new B();&lt;br /&gt;    &lt;br /&gt;    conInsInner(as, b);&lt;br /&gt;  }&lt;/pre&gt;&lt;/td&gt; &lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;h2&gt;Valid operations&lt;/h2&gt;&lt;br /&gt;The upper left and lower right quadrants show valid operations, which are guaranteed not to result in runtime errors and which therefore do not generate compile-time errors.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Covariant extraction&lt;/h3&gt;&lt;br /&gt;The upper left quadrant shows a List of B's passed to a method which retrieves an element as an instance of A and returns it. Simple and working.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Contravariant insertion&lt;/h3&gt;&lt;br /&gt;The lower right quadrant shows a List of A's and a B passed to a method that treats the list as if it were a List of some superclass of B, and adds the B instance to it. Once again, works fine.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Invalid operations&lt;/h2&gt;&lt;br /&gt;The upper right and lower left quadrants show problematic operations, which could potentially cause errors at runtime. The compile-time error is shown in red.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Covariant insertion&lt;/h3&gt;&lt;br /&gt;The lower left quadrant shows an attempt to write a method with a covariant use which attempts to insert an element. The compiler generates an error on the call to add().&lt;br /&gt;&lt;br /&gt;Consider what would happen if the compiler did not flag the call to add(): the method covInsInner would be able to insert &lt;i&gt;any&lt;/i&gt; A into the as list; rather than an A, it could insert a C or any other subtype of A. However, the covariantInsertion method that called covInsInner is using a List of B's, and the insertion of anything that is not a B corrupts the list.&lt;br /&gt;&lt;br /&gt;Java chooses to flag the call to add() as the error, rather than, say, the call to covInsInner, because the call to covInsInner looks correct: bs is a List of something that extends A. The error arises with the call to add() because as is passed as covariant; the "? extends ..." syntax does not modify A, but rather indicates that the List can be used in a covariant manner. And the call to add() is not a covariant usage.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Contravariant extraction&lt;/h3&gt;&lt;br /&gt;The upper right quadrant shows an attempt to write a method with a contravariant use which attempts to extract an element. The compiler generates an error on the call to get().&lt;br /&gt;&lt;br /&gt;Consider what could happen if the compiler did not flag the call to add(): The conExtInner method could extract a B object from a list of A objects, resulting in a class cast error at runtime.&lt;br /&gt;&lt;br /&gt;Java again chooses to flag the call to get() because the type "List&amp;lt;? super B&gt;" marks the List bs as a contravariant usage, and get() is not allowed by that usage.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;The bottom line&lt;/h2&gt;&lt;br /&gt;The syntax "&lt;b&gt;? extends A&lt;/b&gt;" marks the type as a &lt;b&gt;covariant&lt;/b&gt; usage, allowing collections of subtypes of A to be assigned, but only allowing &lt;b&gt;extraction&lt;/b&gt;. The "&lt;b&gt;? super B&lt;/b&gt;" syntax marks the type as a &lt;b&gt;contravariant&lt;/b&gt; usage, allowing collections of supertypes of B to be assigned, but only allowing &lt;b&gt;insertion&lt;/b&gt;. Or, as Naftalin and Wadler put it in &lt;i&gt;Java Generics&lt;/i&gt;,&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;The Get and Put Principle:&lt;/b&gt; use an &lt;b&gt;extends&lt;/b&gt; wildcard when you only &lt;b&gt;get&lt;/b&gt; values out of a structure, use a &lt;b&gt;super&lt;/b&gt; wildcard when you only &lt;b&gt;put&lt;/b&gt; values into a structure, and don't use a wildcard when you &lt;b&gt;both&lt;/b&gt; get and put.&lt;/blockquote&gt;Or, more succintly, &lt;b&gt;extends = covariant = read-only&lt;/b&gt; and &lt;b&gt;super = contravariant = write-only&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;[Edit] Del just reminded me of a key point: The covariant and contravariant markers might appear to modify the type argument to the generic, but they do not. The type List&amp;lt;? extends ...&gt; controls the usage of the List; it does not affect the contents of the list.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-7795840533505213729?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/7795840533505213729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=7795840533505213729' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7795840533505213729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/7795840533505213729'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2010/11/subclassing-and-java-generics-revisited.html' title='Subclassing and Java Generics, revisited'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-2080935900465494266</id><published>2010-10-27T18:24:00.001-05:00</published><updated>2010-10-27T18:24:56.983-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='link'/><category scheme='http://www.blogger.com/atom/ns#' term='programming language'/><title type='text'>Link o' the day: Meditations on Bluish Coder and inadequacy</title><content type='html'>Every once in a while, I run across someone who makes me feel inadequate. (As opposed to the people I work with every day, who make me feel completely adequate.)&lt;br /&gt;&lt;br /&gt;Recently,&amp;nbsp; I have been interested in programming languages with dependent data types, mostly because they seem to be the natural end point of type system evolution. (Perhaps "end point" is the wrong term; "next step" may be better.) Unfortunately, most of the dependently typed languages I have seen are unappealing for various reasons.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.e-pig.org/darcs/Pig09/web/"&gt;Epigram&lt;/a&gt; seems neat, but the last time I looked at it I seem to recall it only worked within its own IDE. Not a terrible failing, but still.... And version 2 is not out yet.&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.portal.chalmers.se/agda/pmwiki.php"&gt;Agda&lt;/a&gt; also seems neat, but for some reason I am having a hard time getting enthusiastic about it.&lt;/li&gt;&lt;li&gt;&lt;a href="http://coq.inria.fr/"&gt;Coq&lt;/a&gt; &lt;i&gt;is&lt;/i&gt; neat (there may be a trend here), but as a programming language? Certainly, it is the best computer game I have played in ages, but one issue I have is that I find Coq proofs almost unreadable. It does get lots of extra points for &lt;a href="http://www.labri.fr/Perso/%7Ecasteran/CoqArt/index.html"&gt;Coq'Art&lt;/a&gt;, a truly excellent book.&lt;/li&gt;&lt;li&gt;Many of the &lt;a href="http://en.wikipedia.org/wiki/Dependent_type"&gt;others&lt;/a&gt; that I have heard about are not actively developed.&lt;/li&gt;&lt;/ul&gt;However, there is one alternative with a significant feature: &lt;a href="http://www.ats-lang.org/"&gt;ATS&lt;/a&gt; has excellent placement in the&lt;a href="http://shootout.alioth.debian.org/"&gt; computer language shootout&lt;/a&gt;. (Hey, that's how I found &lt;a href="http://caml.inria.fr/"&gt;OCaml&lt;/a&gt;, which quickly became my last favorite programming language.) Plus, the current implementation is named "Anairiats", which is both cool and enigmatic.&lt;br /&gt;&lt;br /&gt;To come back around to the point of this post, I was casting around for more information about ATS, and found &lt;a href="http://www.bluishcoder.co.nz/"&gt;Bluish Coder&lt;/a&gt;, the blog of Chris Double, who, judging by the tags and posts, seems to have already done most of the things on my to-do list. Scheme in Javascript, ATS, continuations, factor, etc., etc. Worst of all, he's in New Zealand.&lt;br /&gt;&lt;br /&gt;Damn, I'm inadequate.&lt;br /&gt;&lt;br /&gt;[Edit: Yah, and I can't even remember to tag my posts.]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5087326709910512917-2080935900465494266?l=maniagnosis.crsr.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://maniagnosis.crsr.net/feeds/2080935900465494266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5087326709910512917&amp;postID=2080935900465494266' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2080935900465494266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5087326709910512917/posts/default/2080935900465494266'/><link rel='alternate' type='text/html' href='http://maniagnosis.crsr.net/2010/10/link-o-day-meditations-on-bluish-coder.html' title='Link o&apos; the day: Meditations on Bluish Coder and inadequacy'/><author><name>Tommy McGuire</name><uri>http://www.blogger.com/profile/11707703831241539347</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_5Lbh3COW-VI/TBgFWlgoqII/AAAAAAAAAAM/8_c3RDxriMM/S220/icon.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5087326709910512917.post-4499216958636880009</id><published>2010-10-23T21:11:00.010-05:00</published><updated>2010-11-29T17:00:49.420-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='http'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenAM'/><category scheme='http://www.blogger.com/atom/ns#' term='SAML'/><category scheme='http://www.blogger.com/atom/ns#' term='authentication'/><category scheme='http://www.blogger.com/atom/ns#' term='protocols'/><title type='text'>SAML2 Servlet Filter</title><content type='html'>I have been working on various forms of &lt;a href="http://maniagnosis.crsr.net/search/label/authentication"&gt;authentication for Java-based web applications&lt;/a&gt; for quite a while. The latest iteration uses the &lt;a href="http://maniagnosis.crsr.net/2010/07/saml-authentication-for-web.html"&gt;Security Assertion Markup Language, version 2&lt;/a&gt; to interact with an Identity Provider (IdP), which is supported by the authentication system we get to use. When describing the &lt;a href="http://maniagnosis.crsr.net/2010/08/flexible-osgi-servlet-filters.html"&gt;OSGi-based design&lt;/a&gt; I came up with to support this thingamajig I again mentioned the code to handle the interaction; the first part of that code is the topic of this post. I intend to describe the servlet filter which stands in front of application servlets; a later post will describe the Assertion Consumer Service.&lt;br /&gt;&lt;br /&gt;Because of the way the code is structured, this post must assume that you are familiar with the basic protocol as described in &lt;a href="http://maniagnosis.crsr.net/2010/07/saml-authentication-for-web.html"&gt;SAML authentication for web applications&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Background&lt;/h2&gt;&lt;br /&gt;There are two parts to the application-side (or Service Provider, SP side) of the authentication infrastructure: a servlet filter and the Assertion Consumer Service (or ACS), an application that interprets the SAML response and directs the user's request appropriately. The servlet filter intercepts incoming user requests and either&lt;br /&gt;&lt;ul&gt;&lt;li&gt;passes the request as-is, for those that do not need authentication,&lt;/li&gt;&lt;li&gt;handles redirected requests from the ACS after the authentication,&lt;/li&gt;&lt;li&gt;handles requests that are already authenticated,&lt;/li&gt;&lt;li&gt;does something useful in the case when SAML authentication must be disabled, or&lt;/li&gt;&lt;li&gt;generates an authentication request.&lt;/li&gt;&lt;/ul&gt;The first and fourth options are, well, optional. The SAML2 filter only needs the second, third, and fifth branches to function correctly.&lt;br /&gt;&lt;br /&gt;I do not intend to provide complete code for the filter, because the implementation I have is tightly bound to the OSGi container and to our framework and the idea of refactoring it for genericity leaves a bad taste in my mouth. The basic structure of the filter, though, is:&lt;br /&gt;&lt;pre&gt;try&lt;br /&gt;{&lt;br /&gt;  final HttpServletResponse response = (HttpServletResponse) resp;&lt;br /&gt;  final HttpServletRequest request =&lt;br /&gt;  filteredRequest(new HideClientSsoHeaderHttpRequest((HttpServletRequest) rqst), response, chain, getConfig(config));&lt;br /&gt;  if (request == null) { return; }&lt;br /&gt;  else if (handleAcsRedirect(request, response, chain)) { return; }&lt;br /&gt;  else if (handleAuthenticatedRequest(request, response, chain)) { return; }&lt;br /&gt;  else if (handleSamlDisabled(request, response, chain, getConfig(config))) { return; }&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;    // Unknown key: send Authentication Request&lt;br /&gt;    response.sendRedirect(authnRequest(request));&lt;br /&gt;    return;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;catch (...) { ... }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The possible exceptions are SecuritySystemException, a high-level exception thrown by the authentication and identity-related parts of our framework, usually indicating an operational failure of some sort, and DecoderException, from Apache Commons Codec and indicates a Base64 or other encoding error.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Pass through&lt;/h2&gt;&lt;br /&gt;Passing through requests unfiltered is relatively simple, although there are several related operations and as a result the function is larger than it would seem to be. The filteredRequest function returns either a null, indicating that the request has been handled, or a request which may be the original or may be a modified version. Pass through processing must be done first, since the whole goal is to short-circuit other more expensive processing.&lt;br /&gt;&lt;pre&gt;private HttpServletRequest filteredRequest(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Config config) throws IOException, ServletException&lt;br /&gt;  {&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The basic filter compares the URL from the request with a regular expression pattern; if the URL matches the request is passed on to the next element of the filter chain to be handled and null is returned.&lt;br /&gt;&lt;pre&gt;if (config.excludedUrlPattern != null)&lt;br /&gt;    {&lt;br /&gt;      final String contextPath = request.getContextPath();&lt;br /&gt;      final String requestUri = request.getRequestURI();&lt;br /&gt;      final int contextBeg = requestUri.indexOf(contextPath);&lt;br /&gt;      final int contextEnd = contextBeg + contextPath.length();&lt;br /&gt;      &lt;br /&gt;      String applicationUrl =&lt;br /&gt;          (contextBeg &lt; 0 || contextEnd == (requestUri.length() - 1))&lt;br /&gt;          ? requestUri : requestUri.substring(contextEnd);&lt;br /&gt;      if (!applicationUrl.startsWith("/"))&lt;br /&gt;      {&lt;br /&gt;        applicationUrl = "/" + applicationUrl;&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;      if (config.excludedUrlPattern.matcher(applicationUrl).matches())&lt;br /&gt;      {&lt;br /&gt;        /* Request matches excluded URL pattern; do not continue with filter. */&lt;br /&gt;        chain.doFilter(request, response);&lt;br /&gt;        return null;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;The second option we currently have is for AMF requests (a.k.a. BlazeDS, as in Adobe Flex), it matches against the destination of the request (which requires grubbing through the request, unfortunately). Corey describes what this does as:&lt;blockquote&gt;When a Flex client makes a remote object call this ends making two seperate server calls. The first is an administration call that doesn't have a normal AMF payload (that can be decoded). The second is the call (with payload) to the service destination. Because I can't tell what service destination this is targeted to I'm always letting these administration request go through unfiltered. I need to add a check here when this happens to make sure they are targeting the Flex broker with the URL.&lt;/blockquote&gt;&lt;pre&gt;if (config.excludedAmfDestinationPattern != null&lt;br /&gt;        &amp;&amp; AMF_CONTENT_TYPE.equals(request.getHeader(CONTENT_TYPE_HEADER)))&lt;br /&gt;    {&lt;br /&gt;      final CapturedBytesHttpRequest captureBytesRequest = new CapturedBytesHttpRequest(request);&lt;br /&gt;      final AmfDecoder decoder = new AmfDecoder(captureBytesRequest.getCapturedBytes());&lt;br /&gt;      if (!decoder.decode() || config.excludedAmfDestinationPattern.matcher(decoder.getDestination()).matches())&lt;br /&gt;      {&lt;br /&gt;        /* Request matches AMF destination pattern; do not continue with filter. */&lt;br /&gt;        chain.doFilter(captureBytesRequest, response);&lt;br /&gt;        return null;&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;        return captureBytesRequest;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    return request;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;ACS redirects&lt;/h2&gt;When a request is directed to the ACS which contains a successful authentication, it redirects the browser back to the original URL, meaning that the request is captured by this filter. However, the redirected request (which must be a GET) contains a query parameter matching the regular expression pattern "^ACSREQUESTID=(.*)$". (In-band signaling is kind of unpleasant, but there are few other ways to correctly get the requisite information shared by the ACS, this filter, and the browser.)When a request contains the ACSREQUESTID, the value is picked out and decoded. This value is a token that is used as a key for the authentication information as well as to recover the original request, which is handled by this function.&lt;pre&gt;private boolean handleAcsRedirect(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain)&lt;br /&gt;  throws DecoderException, IOException, ServletException&lt;br /&gt;  {&lt;br /&gt;    final String queryString = request.getQueryString();&lt;br /&gt;    if (queryString != null)&lt;br /&gt;    {&lt;br /&gt;      final Matcher matcher = pat.matcher(queryString);&lt;br /&gt;      if (matcher.matches())&lt;br /&gt;      {&lt;br /&gt;        final String key = new URLCodec().decode(matcher.group(1));&lt;br /&gt;        final HttpServletRequestWrapper storedRequest = Storage.getRequestStore().getRequest(key);&lt;br /&gt;        final IdentityMap mapping = Storage.getIdentityStore().getIdentity(Arrays.asList(key));&lt;br /&gt;        if (storedRequest != null &amp;&amp; mapping != null)&lt;br /&gt;        {&lt;br /&gt;          storedRequest.setRequest(request);          &lt;br /&gt;          chain.doFilter(new AuthenticatedHttpServletRequest(storedRequest, mapping), response);&lt;br /&gt;          Storage.getRequestStore().removeRequest(key);&lt;br /&gt;          return true;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;The Storage class provides access to two different storage systems:&lt;ul&gt;&lt;li&gt;The IdentityStore records information returned from the IdP about a user; the information is returned as an IdentityMap, which is used to construct an AuthenticatedHttpServletRequest.&lt;br /&gt;&lt;pre&gt;public interface IdentityStore&lt;br /&gt;{&lt;br /&gt;  public abstract void storeIdentity(String key, String identity, Map&amp;lt;String, List&amp;lt;String&gt;&gt; attributes, Date expiry);&lt;br /&gt;  public abstract IdentityMap getIdentity(List&lt;string&gt; keys);&lt;br /&gt;  public abstract IdentityMap getIdentity(Identity identity);&lt;br /&gt;  public interface IdentityMap&lt;br /&gt;  {&lt;br /&gt;    public abstract String getEmployeeNumber();&lt;br /&gt;    public abstract Map&amp;lt;String,List&amp;lt;String&gt;&gt; getAttributes();&lt;br /&gt;    public abstract Date getExpiration();&lt;br /&gt;    public abstract boolean valid();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;The RequestStore records the original request from the user (which will be stored below)&lt;br /&gt;&lt;pre&gt;public interface RequestStore&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;  public abstract void storeRequest(String key, HttpServletRequest request);&lt;br /&gt;  public abstract String getRequestUrl(String key);&lt;br /&gt;  public abstract HttpServletRequestWrapper getRequest(String key);&lt;br /&gt;  public abstract void removeRequest(String key);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;The Storage class in turn comes in two forms:&lt;ul&gt;&lt;li&gt;An in-memory store, used for original testing and possibly in case of database failures, and&lt;/li&gt;&lt;li&gt;A database-backed store, used to share requests between load-balanced servers as well as preserving requests in case of server restarts.&lt;/li&gt;&lt;/ul&gt;An AuthenticatedHttpServletRequest recovers a stored request and adds the identity information from the IdentityMap to allow access from the application.&lt;h2&gt;Authenticated requests&lt;/h2&gt;Authenticated requests are simple to handle. The token used as a key store the identity information is also added as a cookie to the response by the ACS, so all this method needs to do is to recover the cookie and check it against the IdentityStore (which includes checking if the authentication has timed out).&lt;pre&gt;private boolean handleAuthenticatedRequest(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain)&lt;br /&gt;  throws DecoderException, IOException, ServletException&lt;br /&gt;  {&lt;br /&gt;    final List&lt;string&gt; authCookie = Misc.getCookie(request, AUTH_COOKIE_NAME);&lt;br /&gt;    final IdentityMap mapping = Storage.getIdentityStore().getIdentity(authCookie);&lt;br /&gt;    if (mapping != null &amp;&amp; mapping.valid())&lt;br /&gt;    {&lt;br /&gt;      chain.doFilter(new AuthenticatedHttpServletRequest(request, mapping), response);&lt;br /&gt;      return true;&lt;br /&gt;    }&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;h2&gt;Disabling SAML&lt;/h2&gt;The downside of the SAML2 single-sign-on design is that if the IdP is down, the applications are also unavailable. As an alternative, I added a administratively configurable flag to disable SAML2 processing. If SAML2 is disabled, there are three other options:&lt;ul&gt;&lt;li&gt;Some applications are already able to handle their own authentication in place of SAML2. For these applications, if SAML2 is disabled all requests are passed on directly to the application.&lt;/li&gt;&lt;li&gt;Some applications may need a generic username and password based authentication scheme; in this case a application-specified page is displayed with a form request a login. Once the user is logged in, normal identity information is available to the application, so the authenticated requests branch above can be taken.&lt;/li&gt;&lt;li&gt;Any remaining applications should simply display an "unavailable" page.&lt;/li&gt;&lt;/ul&gt;I will not show any code for this method, since it is relatively straightforward and the processing for option 2 is lengthy.&lt;h2&gt;Generating authentication requests&lt;/h2&gt;The remaining possibility requires generating an authentication request, storing the original request, and redirecting the browser via the request back to the IdP.&lt;pre&gt;private String authnRequest(HttpServletRequest request) throws SecuritySystemException&lt;br /&gt;  {&lt;br /&gt;    // Generate the session identification key&lt;br /&gt;    final String key = Framework.getSessionKeyService().generateSessionKey();&lt;br /&gt;    Storage.getRequestStore().storeRequest(key, request);&lt;br /&gt;    return new AuthenticationRequest(key).toUriString();&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;The session key generated is used as the token for the SAML2 request as well as the value of the cookie identifying future authenticated requests. The key itself is just a cryptographically secure random number. The String generated is the URL of the IdP with the authentication request added as a query parameter, following the SAML2 specifications. This is passed back to the browser as a redirect.&lt;h2&gt;An AuthenticationRequest&lt;/h2&gt;To interact with the IdP, I used the fmclientsdk.jar and openssoclientsdk.jar libraries from &lt;a href="http://forgerock.com/openam.html"&gt;OpenAM&lt;/a&gt;, which was OpenSSO from Sun before the Oracle acquisition. I currently need to use both, because some classes are missing from each. (I really should report that as a bug.)&lt;pre&gt;public AuthenticationRequest(String key) throws SecuritySystemException&lt;br /&gt;  {&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;      final String destinationUrl = ...;&lt;br /&gt;      final boolean forceAuthn = ...;&lt;br /&gt;      final boolean isPassive = ...;&lt;br /&gt;      final boolean signAuthnRqst = ...;&lt;br /&gt;      final String acsUrl = ...;&lt;br /&gt;&lt;br /&gt;      final AuthnRequest authnRequest = ProtocolFactory.getInstance().createAuthnRequest();&lt;br /&gt;      &lt;br /&gt;      authnRequest.setID(key);&lt;br /&gt;      authnRequest.setVersion(SAML_VERSION);&lt;br /&gt;      authnRequest.setIssueInstant(new Date());&lt;br /&gt;      authnRequest.setDestination(destinationUrl);&lt;br /&gt;      if (forceAuthn)&lt;br /&gt;      {&lt;br /&gt;        authnRequest.setForceAuthn(forceAuthn);&lt;br /&gt;      }&lt;br /&gt;      if (isPassive)&lt;br /&gt;      {&lt;br /&gt;        authnRequest.setIsPassive(isPassive);&lt;br /&gt;      }&lt;br /&gt;      authnRequest.setProtocolBinding(PROTOCOL_BINDING);&lt;br /&gt;      authnRequest.setAssertionConsumerServiceURL(acsUrl); &lt;br /&gt;      authnRequest.setIssuer(issuer());&lt;br /&gt;      authnRequest.setNameIDPolicy(nameIdPolicy());&lt;br /&gt;      authnRequest.setRequestedAuthnContext(requestAuthnContext());&lt;br /&gt;      if (signAuthnRqst)&lt;br /&gt;      {&lt;br /&gt;        sign(authnRequest);&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;      authnRequestMessage = authnRequest.toXMLString(true, true);&lt;br /&gt;      log.debug("request: " + authnRequestMessage);&lt;br /&gt;    }&lt;br /&gt;    catch (SAML2Exception e)&lt;br /&gt;    {&lt;br /&gt;      throw new SecuritySystemException("Unable to create SAML2 AuthnRequest", e);&lt;br /&gt;    }&lt;br /&gt;    catch (...) { ... }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;The com.sun.identity.saml2.protocol.ProtocolFactory class provides access to the components needed to generate the authentication request. The created object is a com.sun.identity.saml2.protocol.AuthnRequest, which has a large number of properties which can be set to fill in elements in the request. For precise details of which properties are needed, see the &lt;a href="http://saml.xml.org/saml-
