<?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-1595066899599866342</id><updated>2011-12-05T18:33:34.551Z</updated><category term='c#'/><category term='architecture'/><category term='general'/><category term='erlang'/><title type='text'>Software Development Redux</title><subtitle type='html'>Intermittent commentary on eclectic software technologies</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://egarson.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1595066899599866342/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://egarson.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Edward Garson</name><uri>http://www.blogger.com/profile/11435021961293665020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1595066899599866342.post-1748355739344756747</id><published>2009-03-10T03:45:00.009Z</published><updated>2010-11-19T21:12:58.411Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><title type='text'>97 Things for Software Architects</title><content type='html'>&lt;p&gt;&lt;a href="http://97-things.near-time.net/wiki"&gt;97 Things Every Software Architect Should Know&lt;/a&gt; has finally been published, and it's been worth the wait. I have watched it germinate all the way from a friend's whimsical idea on a mailing list (&lt;i&gt;"Hey, this would make a good book!"&lt;/i&gt;) to its birth as hardcopy.&lt;/p&gt;&lt;p&gt;I contributed two of the 97 'Things', &lt;a href="http://97-things.near-time.net/wiki/context-is-king-and-simplicity-its-humble-servant"&gt;Context Is King&lt;/a&gt; and &lt;a href="http://97-things.near-time.net/wiki/Heterogeneity%20Wins"&gt;Heterogeneity Wins&lt;/a&gt;. In &lt;b&gt;Context is King&lt;/b&gt;, I postulate that there are no global axioms in the domain of software architecture, but rather that (any) ideal does not live out of context. In &lt;b&gt;Heterogeneity Wins&lt;/b&gt;, I encourage software architects to think outside of the stack, this because I cannot count the number of times that I have consulted on a project where the problem domain was poorly understood, but the technological solution - or, the correct BigCo Framework Extension piece - had already been chosen.&lt;/p&gt;&lt;p&gt;As far as I am aware, &lt;b&gt;97 Things&lt;/b&gt; is the world's first &lt;i&gt;open-source book&lt;/i&gt;, in that all contributions were pre-published and peer-reviewed, and all are Creative Commons-licensed. Furthermore, all of the book's content is available &lt;a href="http://97-things.near-time.net/wiki"&gt;online&lt;/a&gt; so you can &lt;b&gt;try before you buy&lt;/b&gt;. But of course, you can't curl up in bed with the web (the Kindle notwithstanding), so you'll probably still want a dead-tree version :-).&lt;/p&gt; &lt;p&gt;An interesting aspect of the book is how some of the axioms &lt;b&gt;contradict one another&lt;/b&gt;. For example, &lt;a href="http://97-things.near-time.net/wiki/it-s-all-about-performance"&gt;It's all about performance&lt;/a&gt; contradicts my own &lt;a href="http://97-things.near-time.net/wiki/context-is-king-and-simplicity-its-humble-servant"&gt;Context Is King&lt;/a&gt;, because I propose that it is only within scope and business objectives (i.e. context) that an architect has the necessary framework to make the right decisions, while the other promotes the idea that - requirements notwithstanding - nobody wants a system that runs like a snail. (And, while I acknowledge the basic truth of that premise, I would point out that it is context that &lt;i&gt;always&lt;/i&gt; denotes &lt;b&gt;how fast a system should run&lt;/b&gt;, and furthermore that sometimes &lt;b&gt;snail-fast is perfectly acceptable&lt;/b&gt;, e.g. if some other over-arching business goal is met).&lt;/p&gt;&lt;p&gt;It is worth noting that 97 Things will have &lt;b&gt;very good shelf-life&lt;/b&gt; relative to many other software engineering tomes. The advice it contains is fairly generic and technology-agnostic. I favor books that exhibit these qualities, that I know will still be relevant 10 years from now, or (more realistically) after the 6 month lapse has passed between the time I bought it and when I actually found time to study it :-)&lt;/p&gt;&lt;p&gt;Software architecture is a &lt;b&gt;nascent, black art&lt;/b&gt;, and we are still finding our way; I hope within the book you find stimulus and inspiration.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1595066899599866342-1748355739344756747?l=egarson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://egarson.blogspot.com/feeds/1748355739344756747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1595066899599866342&amp;postID=1748355739344756747' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1595066899599866342/posts/default/1748355739344756747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1595066899599866342/posts/default/1748355739344756747'/><link rel='alternate' type='text/html' href='http://egarson.blogspot.com/2009/03/97-things-for-software-architects.html' title='97 Things for Software Architects'/><author><name>Edward Garson</name><uri>http://www.blogger.com/profile/11435021961293665020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1595066899599866342.post-7416910039768720050</id><published>2008-03-26T17:45:00.008Z</published><updated>2008-04-03T12:00:00.594+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>The *Real* Erlang "Hello, World!"</title><content type='html'>&lt;p&gt;This *is not* it:&lt;/p&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;-mod(hello).&lt;br /&gt;-export([start/0]).&lt;br /&gt;&lt;br /&gt;start() -&gt;&lt;br /&gt;  io:format("Hello, World!").&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;I propose that the purpose of a "Hello, World!" program is to communicate something essential about the programming language in a small space. The program above does not achieve this - relative to implementations in other languages - predominantly because it omits anything to do with the &lt;a href="http://en.wikipedia.org/wiki/Actor_model"&gt;Actor model&lt;/a&gt;, which is a core part of what makes &lt;a href="http://en.wikipedia.org/wiki/Erlang_%28programming_language%29"&gt;Erlang&lt;/a&gt; interesting.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I propose that the following should be considered &lt;b&gt;The Real Erlang "Hello, World!":&lt;/b&gt;&lt;/p&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;-module(hello).&lt;br /&gt;-export([start/0]).&lt;br /&gt;&lt;br /&gt;start() -&gt;&lt;br /&gt;   spawn(fun() -&gt; loop() end).&lt;br /&gt;&lt;br /&gt;loop() -&gt;&lt;br /&gt;   receive&lt;br /&gt;      hello -&gt;&lt;br /&gt;         io:format("Hello, World!~n"),&lt;br /&gt;         loop();&lt;br /&gt;      &lt;br /&gt;      goodbye -&gt;&lt;br /&gt;         ok&lt;br /&gt;   end.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Let's dissect this example to see why. To run this program, &lt;a href="http://www.erlang.org/download.html"&gt;install Erlang&lt;/a&gt;, fire up the Erlang REPL &lt;code&gt;erl.exe&lt;/code&gt; and follow along.&lt;/p&gt;&lt;p&gt;First we compile and load the program with the command&lt;code&gt;c()&lt;/code&gt;. Note that we omit the ".erl" file extension when referring to the module. Also note that I started&lt;code&gt;erl.exe&lt;/code&gt; in the directory containing &lt;code&gt;hello.erl&lt;/code&gt; such that I was not required to type in the full path.&lt;/p&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;1&gt; c(hello).&lt;br /&gt;{ok,hello}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Erl responds with &lt;code&gt;ok&lt;/code&gt; and the name of the compiled module.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;start()&lt;/code&gt; function is the only function we can invoke in the &lt;code&gt;hello&lt;/code&gt; module, because it's the only one that is exported, as per the module's &lt;b&gt;export&lt;/b&gt; statement. This is how Erlang implements encapsulation, in that the exported functions form the public interface of the module. The list of exported functions are of the form &lt;b&gt;&lt;code&gt;name/arity&lt;/code&gt;&lt;/b&gt;, where &lt;b&gt;name&lt;/b&gt; is the name of the function and &lt;b&gt;arity&lt;/b&gt; is a formal way of saying "the number of arguments it takes".&lt;/p&gt;&lt;p&gt;Invoke the &lt;code&gt;start()&lt;/code&gt; function within the &lt;code&gt;hello&lt;/code&gt; module, assigning the return value to a variable called &lt;code&gt;Pid&lt;/code&gt;:&lt;/p&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;2&gt; Pid = hello:start(). &lt;br /&gt;&lt;0.36.0&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;The &lt;code&gt;spawn&lt;/code&gt; function returns a &lt;b&gt;Pid&lt;/b&gt; - a &lt;i&gt;Process Identifier&lt;/i&gt; - which is a first-class Erlang data type. We assign this return value to a variable of the same name. (We could just as easily have assigned it to a variable named&lt;code&gt;Foo&lt;/code&gt;, but using &lt;code&gt;Pid&lt;/code&gt; is fairly common). Note that variables in Erlang need to start with an uppercase letter. &lt;/p&gt;&lt;p&gt;Erl responds by pretty printing the process identifier &lt;code&gt;&amp;lt;0.36.0&amp;gt;&lt;/code&gt;; all valid expressions in Erlang have a return value.&lt;/p&gt;&lt;p&gt;At this juncture, if you try to assign any other value to Pid, you will get a &lt;code&gt;badmatch&lt;/code&gt; exception. Once a value has been bound to an identifier, it cannot change: Erlang is a &lt;a href="http://en.wikipedia.org/wiki/Single_assignment"&gt;single-assignment&lt;/a&gt; language. The benefits of this paradigm include the ability for the compiler and runtime to make fancy optimizations, and it also greatly eases debugging because variables are immutable.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;The Sharp End&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;The &lt;code&gt;spawn&lt;/code&gt; invocation starts an &lt;b&gt;Erlang process&lt;/b&gt; which wraps the &lt;code&gt;loop()&lt;/code&gt; function just below it. (Note that Erlang doesn't impose any order of definition on functions). Erlang processes are the essence of programming in Erlang, and the essential missing element in simpler "Hello, World!" examples. Processes are the Erlang implementation of the &lt;a href="http://en.wikipedia.org/wiki/Actor_model"&gt;Actor model&lt;/a&gt;: extremely lightweight concurrency primitives that communicate purely by message-passing. They have nothing whatsoever to do with operating system processes, threads or similar, and are managed entirely by the Erlang runtime. &lt;/p&gt;&lt;p&gt;The process waits (semantically at the &lt;code&gt;receive&lt;/code&gt; statement) for a message which matches one of its &lt;b&gt;receive clauses&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;We can send a message to the process using an exclamation mark (the message-send operator) followed by the message. We can see that the receive block has two clauses which match both &lt;code&gt;hello&lt;/code&gt; and&lt;code&gt;goodbye&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;We invoke the code within the 'hello' clause by sending the corresponding message to our cached Pid:&lt;/p&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;3&gt; Pid ! hello. &lt;br /&gt;Hello, world!&lt;br /&gt;hello&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;As we expect, our process responds with, "Hello, World!". And as noted before, Erlang returns a value for all valid statements, this is why we see &lt;code&gt;hello&lt;/code&gt; printed out immediately following the output of &lt;code&gt;io:format&lt;/code&gt;. &lt;/p&gt;&lt;p&gt;The following line does a &lt;i&gt;tail-recursive&lt;/i&gt; call back to &lt;code&gt;loop()&lt;/code&gt;. In case you didn't follow the link and aren't completely familiar with tail recursion, you should know that &lt;i&gt;&lt;b&gt;tail-recursion is the bombay duck of computer science&lt;/b&gt;&lt;/i&gt;: there is no recursion going on, at least in the sense that anything is left on the stack. Tail recursion is a means of efficiently calling the current function, and is more akin to a goto or a jump instruction than the terminology would have you believe. &lt;/p&gt;&lt;p&gt;So, given the tail-recursive call back to &lt;code&gt;loop()&lt;/code&gt;, the process is once again put back into the wait state. We could send the hello message to Pid ad nauseum and the process would simply repeat.&lt;/p&gt;&lt;p&gt;Now we send the &lt;code&gt;goodbye&lt;/code&gt; message:&lt;/p&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;4&gt; Pid ! goodbye. &lt;br /&gt;goodbye&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;The crucial difference between this clause and the clause that matches the &lt;code&gt;hello&lt;/code&gt; message is that this clause does not include a tail-recursive call back to &lt;code&gt;loop()&lt;/code&gt;. As a result, the process effectively dies. We can confirm this by attempting to invoke the code in the &lt;code&gt;hello&lt;/code&gt; clause once again:&lt;/p&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;5&gt; Pid ! hello. &lt;br /&gt;hello&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;And we see that no output is generated.&lt;/p&gt;&lt;p&gt;The last important detail that I have omitted is the type of &lt;code&gt;hello&lt;/code&gt; and &lt;code&gt;goodbye&lt;/code&gt;. These are erlang &lt;i&gt;atoms&lt;/i&gt;, an extremely simple data type whose value is itself. Atoms are used heavily in message-passing (and other pattern-matching contexts) and are very easy to work with: you simply declare and go!&lt;/p&gt; &lt;br /&gt;&lt;h3&gt;Re-Entry Checklist&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Although the explanation has been verbose, I hope you agree that this Erlang "Hello, World!" communicates some interesting essentials of the Erlang programming language. These essentials concern &lt;i&gt;in particular&lt;/i&gt; how Erlang implements the &lt;a href="http://en.wikipedia.org/wiki/Actor_model"&gt;Actor Model&lt;/a&gt;, which is the kernel of its message-passing semantics and a key enabler for Erlang's capability for massively concurrent processing.&lt;/p&gt;&lt;script&gt;reddit_url='http://egarson.blogspot.com/2008/03/real-erlang-hello-world.html'&lt;/script&gt;&lt;br /&gt;&lt;script&gt;reddit_title='The correct way to do "Hello World" in Erlang'&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://reddit.com/button.js?t=1"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1595066899599866342-7416910039768720050?l=egarson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://egarson.blogspot.com/feeds/7416910039768720050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1595066899599866342&amp;postID=7416910039768720050' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1595066899599866342/posts/default/7416910039768720050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1595066899599866342/posts/default/7416910039768720050'/><link rel='alternate' type='text/html' href='http://egarson.blogspot.com/2008/03/real-erlang-hello-world.html' title='The *Real* Erlang &quot;Hello, World!&quot;'/><author><name>Edward Garson</name><uri>http://www.blogger.com/profile/11435021961293665020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1595066899599866342.post-9030154014019692508</id><published>2008-03-07T17:15:00.045Z</published><updated>2008-04-05T00:40:32.857+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Erlang List Comprehensions: By Necessity</title><content type='html'>&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/List_comprehension"&gt;List comprehensions&lt;/a&gt; are a powerful programming language construct that provide a concise means of dynamically generating lists of values. &lt;a href="http://erlang.org/doc/getting_started/part_frame.html"&gt;Erlang&lt;/a&gt; and Python, amongst other languages, support them.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;There is an interesting observation to be made about Erlang list comprehensions, namely that &lt;i&gt;emergent properties&lt;/i&gt; of Erlang make list comprehensions a practical necessity as opposed to merely being "kewl" syntax.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I had to write a simple function that takes a point &lt;a href="http://gbracha.blogspot.com/2007/02/tuples.html"&gt;tuple &lt;/a&gt;{Row,Column} identifying a square on a bounded plane (think checkers) and return &lt;span style="font-weight: bold;"&gt;the squares that neighbor it&lt;/span&gt; to the north, west, south and east (so to speak).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The bounded plane has point {1,1} in the top-left hand corner, with rows that increment downwards (as per Excel) and columns that increment to the right. So, given the point {2,2}, the function should return {1,2} (the point to the 'north'), {3,2} (south), {2,1} (west) and {2,3} (east). Also, the notion of a bounded plane implies that, given an edge point e.g. {1,2}, the function should return only the &lt;span style="font-style: italic;"&gt;three&lt;/span&gt; points {1,1} (west), {1,3} (east) and {2,2} (south), as there is no point to the north: it is 'out of bounds'. Finally, given a corner point e.g. {1,1}, there are only two neighbors {1,2} (south) and {2,1} (east). Simple enough, yes?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Let's take a look at how this can be implemented in a couple of programming languages before admiring the solution that employs list comprehensions.&lt;/p&gt;&lt;p&gt;Here are the unit tests for what I previously described using C# 2.0 and &lt;a href="http://nunit.org/index.php"&gt;NUnit&lt;/a&gt; 2.4.3.0:&lt;br /&gt;&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void TestFourNeighboredPoint()&lt;br /&gt;{&lt;br /&gt;  IList&amp;lt;Point&amp;gt;neighbors = Point.Neighbors(new Point(2,2));&lt;br /&gt;  Point[] expectedNeighbors = new Point[4] { new Point(1,2), new Point(3,2), new Point(2,1), new Point(2,3) };&lt;br /&gt;&lt;br /&gt;  Assert.IsTrue(neighbors.Count == 4);&lt;br /&gt;  Assert.IsTrue(Array.TrueForAll(expectedNeighbors, delegate(Point p) { return neighbors.Contains(p); }));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void TestThreeNeighboredPoint()&lt;br /&gt;{&lt;br /&gt;  IList&amp;lt;Point&amp;gt; neighbors = Point.Neighbors(new Point(1,2));&lt;br /&gt;  Point[] expectedNeighbors = new Point[3] { new Point(1,1), new Point(1,3), new Point(2,2) };&lt;br /&gt;&lt;br /&gt;  Assert.IsTrue(neighbors.Count == 3);&lt;br /&gt;  Assert.IsTrue(Array.TrueForAll(expectedNeighbors, delegate(Point p) { return neighbors.Contains(p); }));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void TestTwoNeighboredPoint()&lt;br /&gt;{&lt;br /&gt;  IList&amp;lt;Point&amp;gt; neighbors = Point.Neighbors(new Point(1,1));&lt;br /&gt;  Point[] expectedNeighbors = new Point[2] { new Point(1,2), new Point(2,1) };&lt;br /&gt;&lt;br /&gt;  Assert.IsTrue(neighbors.Count == 2);&lt;br /&gt;  Assert.IsTrue(Array.TrueForAll(expectedNeighbors, delegate(Point p) { return neighbors.Contains(p); }));&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(Aside: I use both a generic IList&amp;lt;point&amp;gt; and a Point[] so I can Array.TrueForAll(), which is something of a poor man's &lt;a href="http://www.ruby-doc.org/core-1.9/classes/Array.html#M002201"&gt;Array#map&lt;/a&gt;. This way we avoid having to iterate, thus keeping the code very concise, but at the expense of this anomaly).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Now, the implementation of Point.Neighbors written in a curly-brace language - i.e. without the benefit of list comprehensions - could resemble something like the following C# 2.0:&lt;br /&gt;&lt;/p&gt;&lt;span style="font-family:monospace;"&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;internal static IList&amp;lt;Point&amp;gt; Neighbors(Point p)&lt;br /&gt;{&lt;br /&gt;  IList&amp;lt;Point&amp;gt; neighbors = new List&amp;lt;Point&amp;gt;();&lt;br /&gt;&lt;br /&gt;  if (p.Row - 1 &amp;gt; 0)&lt;br /&gt;    neighbors.Add(new Point(p.Row - 1, p.Column)); // north&lt;br /&gt;&lt;br /&gt;  if (p.Row + 1 &amp;lt;= MAP_SIZE)&lt;br /&gt;    neighbors.Add(new Point(p.Row + 1, p.Column)); // south&lt;br /&gt;&lt;br /&gt;  if (p.Column - 1 &amp;gt; 0)&lt;br /&gt;    neighbors.Add(new Point(p.Row, p.Column - 1)); // west&lt;br /&gt;&lt;br /&gt;  if (p.Column + 1 &amp;lt;= MAP_SIZE)&lt;br /&gt;    neighbors.Add(new Point(p.Row, p.Column + 1)); // east&lt;br /&gt;&lt;br /&gt;  return neighbors;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/span&gt;&lt;p&gt;This code obviously works because the temporary variable &lt;span style="font-weight: bold;font-family:courier new;" &gt;neighbors&lt;/span&gt; is &lt;span style="font-style: italic;"&gt;mutable&lt;/span&gt;. We &lt;span style="font-style: italic;"&gt;mutate &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;neighbors&lt;/span&gt; (i.e. change its value) depending on the bounds we check on the &lt;span style="font-weight: bold;font-family:courier new;" &gt;Row &lt;/span&gt;and &lt;span style="font-weight: bold;font-family:courier new;" &gt;Column &lt;/span&gt;of the given &lt;span style="font-weight: bold;font-family:courier new;" &gt;Point p&lt;/span&gt;.&lt;/p&gt;&lt;p style="color: rgb(0, 0, 0);"&gt;Now, this code doesn't translate into Erlang very elegantly at all (to put it mildly), because &lt;span style="font-style: italic;"&gt;Erlang doesn't support mutable variables&lt;/span&gt;. In Erlang, after a value has been bound to an identifier, &lt;span style="font-weight: bold; font-style: italic;"&gt;the value &lt;/span&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;cannot change&lt;/span&gt;. This language property is known as &lt;b&gt;single-assignment&lt;/b&gt; and is not unique to Erlang. So, Erlang doesn't really have variables, at least if we take the term literally, in the sense that they can &lt;span style="font-style: italic;"&gt;vary&lt;/span&gt;.&lt;/p&gt;&lt;p&gt;To illustrate what impact single assignment has on code written in the style above, here is the closest possible translation of the curly-brace code above in Erlang:&lt;/p&gt;&lt;p&gt;&lt;b&gt;!! DO NOT DO THIS !!&lt;/b&gt;&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;if&lt;br /&gt;  % Normal case: not on any boundary&lt;br /&gt;  Row &amp;gt; 1, Col &amp;gt; 1, Row &amp;lt; ?MAP_SIZE, Col &amp;lt; ?MAP_SIZE -&amp;gt;&lt;br /&gt;    [{Row-1, Col}, {Row, Col+1}, {Row+1, Col}, {Row, Col-1}];&lt;br /&gt;&lt;br /&gt;  % Row is 1, but Col is not on a boundary&lt;br /&gt;  Row == 1, Col &amp;gt; 1, Col &amp;lt; ?MAP_SIZE -&amp;gt;&lt;br /&gt;    [{Row, Col+1}, {Row+1, Col}, {Row, Col-1}];&lt;br /&gt;&lt;br /&gt;  % Col is 1, but Row not on a boundary&lt;br /&gt;  Col == 1, Row &amp;gt; 1, Row &amp;lt; ?MAP_SIZE -&amp;gt;&lt;br /&gt;    [{Row-1, Col}, {Row, Col+1}, {Row+1, Col}];&lt;br /&gt;&lt;br /&gt;  % Row is boundary, Col not on a boundary&lt;br /&gt;  Row == ?MAP_SIZE, Col &amp;gt; 1, Col &amp;lt; ?MAP_SIZE -&amp;gt;&lt;br /&gt;    [{Row, Col-1}, {Row-1, Col}, {Row, Col+1}];&lt;br /&gt;&lt;br /&gt;  % Row not boundary, Col on boundary&lt;br /&gt;  Row &amp;gt; 1, Row &amp;lt; ?MAP_SIZE, Col == ?MAP_SIZE -&amp;gt;&lt;br /&gt;    [{Row-1, Col}, {Row, Col-1}, {Row+1, Col}];&lt;br /&gt;&lt;br /&gt;  % Corner case top left&lt;br /&gt;  Row == 1, Col == 1 -&amp;gt;&lt;br /&gt;    [{1,2},{2,1}];&lt;br /&gt;&lt;br /&gt;  % Corner case bottom left&lt;br /&gt;  Row == ?MAP_SIZE, Col == 1 -&amp;gt;&lt;br /&gt;    [{?MAP_SIZE-1, Col}, {?MAP_SIZE, Col+1}];&lt;br /&gt;&lt;br /&gt;  % Corner case top right&lt;br /&gt;  Row == 1, Col == ?MAP_SIZE -&amp;gt;&lt;br /&gt;    [{Row, Col-1}, {Row+1, Col}];&lt;br /&gt;&lt;br /&gt;  % Corner case bottom right&lt;br /&gt;  Row == ?MAP_SIZE, Col == ?MAP_SIZE -&amp;gt;&lt;br /&gt;    [{?MAP_SIZE, ?MAP_SIZE-1}, {?MAP_SIZE-1, ?MAP_SIZE}];&lt;br /&gt;&lt;br /&gt;  % else&lt;br /&gt;  true -&amp;gt;&lt;br /&gt;    io:format("Logic error! Row: ~p Col: ~p", [Row, Col]),&lt;br /&gt;    error&lt;br /&gt;end.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because Erlang doesn't support mutable variables, we're forced to check every condition prior to assigning the return value. In this instance, we only need to check four basic conditions but the possible permutations of the result set leads to  verbose (and unmaintainable) code. So, how can we elegantly satisfy our requirement in Erlang?&lt;br /&gt;&lt;/p&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;List Comprehensions to the Rescue&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;p&gt;As you've probably guessed by now, the proper way to satisfy this requirement is to use a list comprehension:&lt;/p&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;adjacent_points({Row,Col}) -&amp;gt;&lt;br /&gt;  [{R1,C1} || {R1,C1} &amp;lt;- [{Row-1,Col}, {Row+1,Col}, {Row, Col-1}, {Row, Col+1}],&lt;br /&gt;               R1 &amp;gt; 0, R1 =&amp;lt; ?MAP_SIZE, C1 &amp;gt; 0, C1 =&amp;lt; ?MAP_SIZE].&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Believe it or not, these two lines of code replace the dozen or so lines of code of C#, not to mention the naive Erlang implementation.&lt;/p&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Anatomy of a List Comprehension&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;p&gt;List comprehensions are powerful, because they enable creating lists from one or more source lists, and they emit values that can be selectively filtered using one or more &lt;span style="font-style: italic;"&gt;filters&lt;/span&gt;.&lt;/p&gt;&lt;p&gt;Erlang list comprehensions are enclosed in square brackets. The initial &lt;span style="font-size:100%;"&gt;&lt;span style="font-family:courier new;"&gt;{R1,C1}&lt;/span&gt;&lt;/span&gt; preceding the &lt;span style="font-weight: bold;"&gt;||&lt;/span&gt; is the &lt;span style="font-style: italic;"&gt;constructor&lt;/span&gt;, which can be any expression. In this example, it will simply instantiate the point tuples that we want to generate:&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new;"&gt;[ &lt;span style="font-weight: bold;"&gt;{R1,C1}&lt;/span&gt; || ... ]&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Immediately following the &lt;span style="font-weight: bold;"&gt;||&lt;/span&gt; is a &lt;span style="font-style: italic;"&gt;generator&lt;/span&gt; which is composed of a &lt;span style="font-style: italic;"&gt;pattern&lt;/span&gt; &lt;span style="font-family:courier new;"&gt;{R1,C1}&lt;/span&gt;, followed by &lt;span style="font-weight: bold;font-family:courier new;" &gt;"&lt;-"&lt;/span&gt;, followed by the list. In our case, the list is simply in-lined:&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=";font-family:courier new"  &gt;&lt;span style="font-family:courier new;"&gt;[ {R1,C1} || &lt;span style="font-weight: bold;"&gt;{R1,C1} &lt;- &lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;[{Row-1,Col}, {Row+1,Col}, {Row, Col-1}, {Row, Col+1}]&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;, ... ]&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Each of the generated values in a list comprehension must satisfy &lt;span style="font-weight: bold;font-size:100%;" &gt;all &lt;/span&gt;of the &lt;span style="font-style: italic" &gt;filters&lt;/span&gt; that are specified in the list comprehension (if any). In our case, there are four filters, each of which equate to the conditions that we check in the curly-brace implementation, but with far less baggage:&lt;/p&gt;&lt;p&gt;&lt;span style=";font-family:courier new;"  &gt;&lt;span style="font-family:courier new;"&gt;R1 &gt; 0, R1 =&lt; ?MAP_SIZE, C1 &gt; 0, C1 =&lt; ?MAP_SIZE&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Again, each of the tuples emitted by the &lt;span style="font-style: italic;"&gt;generator&lt;/span&gt; will be checked against each of these filters. All of the filters must be satisfied (i.e. evaluate to true) for the &lt;span style="font-style: italic;"&gt;constructor&lt;/span&gt; part to be invoked. These filters will evaluate to false for tuples that are out of bounds.&lt;/p&gt;&lt;p&gt;Even though our example used a single generator and multiple filters, it should be noted that list comprehensions can be &lt;span style="font-style: italic;"&gt;any&lt;/span&gt; arbitrary number of generators or filters. You should also be aware of Erlang's facility to efficiently generate bit strings with &lt;a href="http://erlang.org/documentation/doc-5.6.1/doc/reference_manual/expressions.html#6.23"&gt;Bit String Comprehensions&lt;/a&gt;, which work very similarly to what we have just seen.&lt;/p&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Re-Entry Checklist&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;p&gt;It is a curious property that the incidence of defects in software &lt;span style="font-weight: bold;"&gt;remains &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;constant&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;span style="font-style: italic;"&gt;irrespective of the number of lines of code written&lt;/span&gt;. Thus as an industry, we should be naturally inclined to use concise languages. List comprehensions are &lt;span style="font-style: italic;"&gt;one&lt;/span&gt; way that Erlang affords a &lt;span style="font-weight: bold;"&gt;succinct notation&lt;/span&gt;. Succinct programming languages exhibit less defects than their more verbose counterparts because there is simply &lt;span style="font-style: italic;"&gt;less room for error&lt;/span&gt;. Some programmers assert that this leads to more obtuse syntax, but in consideration of the constant defect ratio, I believe that this trade off is fully justified.&lt;/p&gt;&lt;span style="font-size:130%;font-weight: bold;"&gt;Afterword&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;p&gt;My thanks to &lt;a href="http://darynholmes.wordpress.com/"&gt;Daryn Holmes&lt;/a&gt; and &lt;a href="http://workingwithmrb.blogspot.com/"&gt;Darren Bishop&lt;/a&gt; for providing several illuminating, alternative implementations of the code above in various programming languages, and to the folks on #erlang IRC.&lt;/p&gt;&lt;script&gt;var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");&lt;br /&gt;document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;&lt;br /&gt;var pageTracker = _gat._getTracker("UA-3485284-1");&lt;br /&gt;pageTracker._initData();&lt;br /&gt;pageTracker._trackPageview();&lt;br /&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1595066899599866342-9030154014019692508?l=egarson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://egarson.blogspot.com/feeds/9030154014019692508/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1595066899599866342&amp;postID=9030154014019692508' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1595066899599866342/posts/default/9030154014019692508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1595066899599866342/posts/default/9030154014019692508'/><link rel='alternate' type='text/html' href='http://egarson.blogspot.com/2008/03/erlang-list-comprehensions-by-necessity.html' title='Erlang List Comprehensions: By Necessity'/><author><name>Edward Garson</name><uri>http://www.blogger.com/profile/11435021961293665020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1595066899599866342.post-5778495958547118190</id><published>2008-01-21T16:12:00.001Z</published><updated>2008-04-05T00:56:35.929+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>History, Santayana, and The Next Big Thing</title><content type='html'>"Those who cannot remember the past are doomed  to repeat it"&lt;br /&gt;&lt;br /&gt;       -  &lt;a href="http://en.wikipedia.org/wiki/George_Santayana"&gt;George Santayana&lt;/a&gt; (1863 - 1952)&lt;br /&gt;&lt;br /&gt;Or put another way, those who do not &lt;span style="font-style: italic;"&gt;learn&lt;/span&gt; about the past are doomed to repeat it.&lt;br /&gt;&lt;br /&gt;And so it goes in our industry. Many of the so-called latest developments are nothing more than a re-hash of ideas from yesteryear. Ask any &lt;a href="http://en.wikipedia.org/wiki/Smalltalk"&gt;Smalltalk&lt;/a&gt; curmudgeon and she'll tell you this is true.&lt;br /&gt;&lt;br /&gt;The statement above is also what makes learning &lt;a href="http://www.paulgraham.com/power.html"&gt;Lisp&lt;/a&gt; (or Smalltalk, &lt;span style="font-size:78%;"&gt;or ...&lt;/span&gt;) &lt;span style="font-weight: bold;"&gt;really and truly worthwhile&lt;/span&gt;: it's &lt;span style="font-style: italic;"&gt;not&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;because you're going to get paid to do any work in those languages (and if you are, then &lt;span style="font-style: italic;"&gt;more power to you&lt;/span&gt; &lt;span style="font-style: italic;"&gt;...&lt;/span&gt;&lt;span style="font-style: italic;font-size:78%;" &gt;and tell me where I can apply...!&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;George Santayana certainly had a lot to say about software development.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;The Next Big Thing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Closely related to this &lt;a href="http://en.wikipedia.org/wiki/Meme"&gt;meme&lt;/a&gt; is that of where to find &lt;span style="font-style: italic;"&gt;The Next Big Thing&lt;/span&gt;. Quite often the answer is sitting on the end of our collective noses. Rather than seek out TNBT in the cyber ether, simply look at your hard drive.&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Witness &lt;a href="http://en.wikipedia.org/wiki/Ajax_%28programming%29"&gt;AJAX&lt;/a&gt;: the enabling technologies (&lt;a href="http://en.wikipedia.org/wiki/XMLHttpRequest"&gt;XMLHttpRequest&lt;/a&gt;, &lt;a href="http://www.xml.com/axml/testaxml.htm"&gt;XML&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Dynamic_html"&gt;Dynamic HTML&lt;/a&gt;) were sitting on everybody's machines several years before somebody creative put these existing pieces together in a new and interesting way.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;But Anybody Could Have Done That!&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;Yes, but &lt;span style="font-style: italic;"&gt;they&lt;/span&gt; didn't.&lt;br /&gt;&lt;br /&gt;There is a great story - probably apocryphal - about Christopher Columbus receiving an accolade for his discovery of the Americas at a banquet. A courtier present at the time remarked, "Well, all you really did was to sail in one direction for a long time - anybody could have done that". Columbus paused for a moment and picked up an egg. "Can you make this egg stay upright?", Columbus asked the courtier. "Of course not!", the courtier replied. Columbus then sharply struck the bottom of the egg on the table, making it stand up, breaking it in the process. "Anybody could have done that!" the courtier protested. "Yes", Columbus replied, "&lt;span style="font-style: italic;"&gt;but&lt;/span&gt; &lt;span style="font-style: italic;"&gt;you didn't."&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Christopher Columbus certainly had a lot to say... erm, never mind....&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;And with this I launch my blog, &lt;a href="http://egarson.blogspot.com/"&gt;Software Development Redux&lt;/a&gt;, with &lt;span style="font-style: italic;"&gt;redux&lt;/span&gt; taken from the Latin meaning, &lt;span style="font-style: italic;"&gt;brought back&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Thanks for visiting.&lt;br /&gt;&lt;script type="text/javascript"&gt;&lt;br /&gt;var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");&lt;br /&gt;document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;&lt;br /&gt;var pageTracker = _gat._getTracker("UA-3485284-1");&lt;br /&gt;pageTracker._initData();&lt;br /&gt;pageTracker._trackPageview();&lt;br /&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1595066899599866342-5778495958547118190?l=egarson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://egarson.blogspot.com/feeds/5778495958547118190/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1595066899599866342&amp;postID=5778495958547118190' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1595066899599866342/posts/default/5778495958547118190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1595066899599866342/posts/default/5778495958547118190'/><link rel='alternate' type='text/html' href='http://egarson.blogspot.com/2008/01/history-santayana-and-next-big-thing.html' title='History, Santayana, and The Next Big Thing'/><author><name>Edward Garson</name><uri>http://www.blogger.com/profile/11435021961293665020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
