Blog of Stuff: Posts tagged 'Programming Languages'urn:http-www-brinckerhoff-org:-tags-Programming-Languages-html2017-08-22T11:59:33Zontologies OF programsurn:http-www-brinckerhoff-org:-blog-2017-08-22-ontologies-of-programs2017-08-22T11:59:33Z2017-08-22T11:59:33ZJohn Clements
<p>Reading Daniel Dennett’s “From Bacteria to Bach and Back” this morning, I came across an interesting section where he extends the notion of ontology—a “system of things that can be known”—to programs. Specifically, he writes about what kinds of things a GPS program might know about: latitudes, longitudes, etc.</p>
<p>I was struck by the connection to the “data definition” part of the design recipe. Specifically, would it help beginning programmers to think about “the kinds of data that their program ‘knows about’”? This personification of programs can be seen as anti-analytical, but it might help students a lot.</p>
<p>Perhaps I’ll try it out this fall and see how it goes.</p>
<p>Okay, that’s all.</p>loops hurt so badurn:http-www-brinckerhoff-org:-blog-2017-05-20-loops-hurt-so-bad2017-05-20T21:18:42Z2017-05-20T21:18:42ZJohn Clements
<p>Why, professor Clements, why? Why are you taking all of our loops away?</p>
<p>I feel like the Grinch, sometimes, taking all of the pretty little candy loops away from the wide-eyed first-year students.</p>
<p>But the fact is… that I really don’t like loops.</p>
<ul>
<li>
<p>Loops in every popular language simply execute a block of code repeatedly. This means that your code has to perform mutation in order to allow a value to escape from the code. This requires before-and-after reasoning, and introduces a huge new source of bugs into your program. By contrast, there’s almost no chance to tangle the action of the caller and the callee in a recursive call.</p></li>
<li>
<p>Corollary of this: you can easily update loop variables in the wrong order: e.g.: i += 1, sum += arr[i]. Oops, bug.</p></li>
<li>
<p>Loops can’t easily be debugged; in a functional style, each loop iteration is a recursive call for which the student can write an explicit test. Not possible using loops.</p></li>
<li>
<p>In functional style, you can’t forget to update a variable; each recursive call must contain values for all loop variables, or you get a sensible (and generally statically detectable) error.</p></li>
<li>
<p>You can’t write a loop in a non-tail-calling fashion. You have to do all of the work on the way down. Traversing a tree is basically impossible (to do it, you’re going to wind up building a model of the stack, turing tar pit etc.).</p></li>
<li>
<p>Finally, writing in a functional style is about 80% of the way to proving your code correct; you have to choose a name for the action of the recursive call, and you can usually state an invariant on the relation between the inputs and the outputs without difficulty.</p></li></ul>
<p>Nothing here is new; it’s just a way of blowing off steam while grading my students’ terrible, terrible code. Sigh.</p>
<p>(EDIT: I should add… none of this applies to list comprehension forms such as for/list; those are dandy. Not sure? Run down the list of bullet points and check for yourself.)</p>restrictive or: notes from the dark sideurn:http-www-brinckerhoff-org:-blog-2017-04-26-restrictive-or-notes-from-the-dark-side2017-04-26T14:33:13Z2017-04-26T14:33:13ZJohn Clements
<p>Okay, it’s week four of data structures in Python. In the past few days, I’ve read a lot of terrible code. Here’s a <em>beautiful</em>, <em>horrible</em>, example:</p>
<div class="brush: Python">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="c1"># An IntList is one of</span>
<span class="c1"># - None, or</span>
<span class="c1"># - Pair(int, IntList)</span>
<span class="k">class</span> <span class="nc">Pair</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">first</span><span class="p">,</span> <span class="n">rest</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">first</span> <span class="o">=</span> <span class="n">first</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rest</span> <span class="o">=</span> <span class="n">rest</span>
<span class="c1"># standard definitions of __eq__ and __repr__ ...</span>
<span class="c1"># A Position is one of</span>
<span class="c1"># - an int, representing a list index, or</span>
<span class="c1"># - None</span>
<span class="c1"># IntList int -> Position</span>
<span class="c1"># find the position of the sought element in the list, return None if not found.</span>
<span class="k">def</span> <span class="nf">search</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">sought</span><span class="p">):</span>
<span class="k">if</span> <span class="n">l</span> <span class="o">==</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="n">rest_result</span> <span class="o">=</span> <span class="n">search</span><span class="p">(</span><span class="n">l</span><span class="o">.</span><span class="n">rest</span><span class="p">,</span> <span class="n">sought</span><span class="p">)</span>
<span class="k">if</span> <span class="p">(</span><span class="n">l</span><span class="o">.</span><span class="n">first</span> <span class="o">==</span> <span class="n">sought</span> <span class="ow">or</span> <span class="n">rest_result</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">if</span> <span class="n">l</span><span class="o">.</span><span class="n">first</span> <span class="o">==</span> <span class="n">sought</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">0</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">rest_result</span>
</pre></div></td></tr></tbody></table></div>
</div>
<p>This code <em>works correctly</em>. It searches a list to find the position of a given element. Notice anything interesting about it?</p>
<p>Take a look at the parentheses in the <code>if</code> line. How do you feel about this code now?</p>
<p>(Spoilers after the jump. Figure out why it works before clicking, and how to avoid this problem.)</p>
<!-- more-->
<p>Okay, that’s just awful. The intent was to write</p>
<div class="brush: Python">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal">1</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">l</span><span class="o">.</span><span class="n">first</span> <span class="o">==</span> <span class="n">sought</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">rest_result</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">):</span>
</pre></div></td></tr></tbody></table></div>
</div>
<p>instead of</p>
<div class="brush: python">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal">1</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">l</span><span class="o">.</span><span class="n">first</span> <span class="o">==</span> <span class="n">sought</span> <span class="ow">or</span> <span class="n">rest_result</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span>
</pre></div></td></tr></tbody></table></div>
</div>
<p>… but the student misparenthesized. The student’s code works because if <code>l.first</code> is equal to <code>sought</code>, the <code>or</code> evaluates to <code>True</code>, which is in fact not equal to <code>None</code>, so you wind up in the right place. Otherwise, the <code>or</code> winds up being the value of rest_result, which is then correctly compared to <code>None</code>. Note also that there’s no <code>else</code> case, meaning that the function secretly returns <code>None</code> in the fall-through, which is also correct.</p>
<p>I hope you agree with me that this code is abominable, and we’d like to prevent students from writing it.</p>
<p>What’s the fix? I think the obvious fix is to ensure that <code>or</code> only works on booleans. This is guaranteed by most typed languages in the type system, or by a dynamic check in the implementation of <code>or</code>.</p>
<p>Does Racket have this problem? No, it does not. In the case of Racket, though, it’s because of the notion of “student languages,” an idea to which many people pay lip service but which few people actually carry out.</p>
<p>Anyway: types or language levels FTW. Or, more precisely:</p>
<p>Python FTL!</p>Not liking Python any better nowurn:http-www-brinckerhoff-org:-blog-2017-03-11-not-liking-python-any-better-now2017-03-12T03:33:25Z2017-03-12T03:33:25ZJohn Clements
<p>It’s much closer to ‘go’ time now with Python, and I must say, getting to know Python better is <em>not</em> making me like it better. I know it’s widely used, but it really has many nasty bits, <em>especially</em> when I look toward using it for teaching. Here’s my old list:</p>
<ul>
<li>Testing framework involves hideous boilerplate.</li>
<li>Testing framework has standard problems with floating-point numbers.</li>
<li>Scoping was clearly designed by someone who’d never taken (or failed to pay attention in) a programming languages course.</li>
<li>The vile ‘return’ appears everywhere.</li></ul>
<p>But wait, now I have many more, and I’m a bit more shouty:</p>
<ul>
<li>Oh dear lord, I’m going to have to force my students to implement their own equality method in order to get test-case-intensional checking. Awful. Discovering this was the moment when I switched from actually writing Python to writing Racket code that generates Python. Bleah.</li>
<li>Python’s timing mechanism involves a hideously unhygienic “pass me a string representing a program” mechanism. Totally dreadful. Worse than C macros.</li>
<li>Finally, I just finished reading <a href="http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html">Guido Van Rossum’s piece on tail-calling</a>, and I find his arguments not just unconvincing, not just wrong, but sort of deliberately insulting. His best point is his first: TRE (or TCO or just proper tail-calling) <em>can</em> reduce the utility of stack traces. However, the solution of translating this code to loops destroys the stack traces too! You can argue that you lose stack frames in those instances in which you make tail calls that are not representable as loops, and in that case I guess I’d point you to our <a href="http://dl.acm.org/citation.cfm?id=1034778">work with continuation marks</a>. His next point can be paraphrased as “If we give them nice things, they might come to depend on them.” Well, yes. His third point suggests to me that he’s tired of losing arguments with Scheme programmers. Fourth, and maybe this is the most persuasive, he points out that Python is a poorly designed language and that it’s not easy for a compiler to reliably determine whether a call is in tail position. Actually, it looks like he’s wrong even here; I read it more carefully, and he’s getting hung up on some extremely simple scoping issues. I’m really not impressed by GvR as a language designer.</li></ul>things I already dislike about Pythonurn:http-www-brinckerhoff-org:-blog-2016-05-16-things-i-already-dislike-about-python2016-05-16T16:55:56Z2016-05-16T16:55:56ZJohn Clements
<p>I’m just getting started, but already Python is looking like a terrible teaching language, relative to Racket.</p>
<ul>
<li>Testing framework involves hideous boilerplate.</li>
<li>Testing framework has standard problems with floating-point numbers.</li>
<li>Scoping was clearly designed by someone who’d never taken (or failed to pay attention in) a programming languages course.</li>
<li>The vile ‘return’ appears everywhere.</li></ul>programs are not sequences of instructionsurn:http-www-brinckerhoff-org:-blog-2016-05-16-programs-are-not-sequences-of-instructions2016-05-16T15:10:12Z2016-05-16T15:10:12ZJohn Clements
<p>Oh mainstream programmers, how I hate thee. Let me count the ways.</p>
<p>The following is a question taken from the “AP Computer Science Principles Course and Exam Description,” from the College Board:</p>
<ol>
<li>A programmer completes the user manual for a video game she has developed and realizes she has reversed the roles of goats and sheep throughout the text. Consider the programmer’s goal of changing all occurences of “goats” to “sheep” and all occurrences of “sheep” to “goats.” The programmer will use the fact that the word “foxes” does not appear anywhere in the original text.</li></ol>
<p>Which of the following algorithms can be used to accomplish the programmer’s goal?</p>
<p>a)</p>
<ul>
<li>First, change all occurrences of “goats” to “sheep.”</li>
<li>Then, charge all occurrences of “sheep” to “goats.”</li></ul>
<p>b)</p>
<ul>
<li>First, change all occurrences of “goats” to “sheep.”</li>
<li>Then, charge all occurrences of “sheep” to “goats.”</li>
<li>Last, charge all occurrences of “foxes” to “sheep.”</li></ul>
<p>c)</p>
<ul>
<li>First, change all occurrences of “goats” to “foxes.”</li>
<li>Then, charge all occurrences of “sheep” to “goats.”</li>
<li>Last, charge all occurrences of “foxes” to “sheep.”</li></ul>
<p>d)</p>
<ul>
<li>First, change all occurrences of “goats” to “foxes.”</li>
<li>Then, charge all occurrences of “foxes” to “sheep.”</li>
<li>Last, charge all occurrences of “sheep” to “goats.”</li></ul>
<p>This question makes me angry. Why? Because the obvious lesson from this example is that YOU SHOULD NOT BE MODELING COMPUTATION AS A SEQUENCE OF MUTATIONS.</p>
<p>In other words, the correct answer is this:</p>
<p>e) For each word in the document, replace it using this function: * if the word is “goats”, return “sheep” * if the word is “sheep”, return “goats” * otherwise, return the word unchanged.</p>
<p>Voila. Problem solved. No resorting to nasty swap ideas.</p>
<p>At a lower level, I think the core problem may be the inability of the English language to handle this kind of abstraction. Notice that in my proposed solution (e), I tread dangerously close to mathematical notation; it’s not really purely English any more.</p>Racket Sucks, Don't Try Iturn:http-www-brinckerhoff-org:-blog-2016-04-25-racket-sucks-don-t-try-it2016-04-25T14:29:05Z2016-04-25T14:29:05ZJohn Clements
<p>I’ve done a lot of programming in Racket. A <em>lot</em>. And people often ask me: “What do you think of Racket? Should I try it?”</p>
<p>The answer is simple: No. No, you should not.</p>
<p>You’re the kind of person who would do very badly with Racket. Here’s why:</p>
<ul>
<li>
<p>All those parentheses! Good Lord, the language is <em>swimming</em> in parentheses. It’s not uncommon for a line to end with <em>ten</em> or <em>twelve</em> parentheses.</p></li>
<li>
<p>Almost no mutation! Idiomatic Racket code doesn’t set the values of variables in loops, and it doesn’t set the values of result variables in <code>if</code> branches, and you can’t declare variables without giving them values, and Racket programmers hardly ever use classes with mutable fields. There’s no <code>return</code> at all. It’s totally not like Java or C. It’s very strange and unsettling.</p></li>
<li>
<p>Library support. Yes, there are lots of libraries available for Racket, but there are many more in, say, Python. I think there are currently fifty-five <em>thousand</em> packages available for Python.</p></li>
<li>
<p>Racket is an experimental language: when the Racket team decides that the language should change, it does. Typed Racket is evolving rapidly, and even core Racket is getting fixes and new functionality every day.</p></li>
<li>
<p>Racket is not a popular language. You’re not going to be able to search for code snippets on line with anything like the success rate that you’d have for JavaScript or Python or Java.</p></li>
<li>
<p>Racket will ruin you for life as a Java developer. You will be agonizingly aware of how much boilerplate you’re cranking out, and after every hour of shoveling Java, you will sneak off to the bathroom and write a tiny beautiful macro that no one will ever be allowed to see or use.</p></li></ul>
<p>If none of these succeed in scaring you off, well, then, go ahead and give it a try. Just remember: I warned you.</p>Break it! Confrontational thinking in computer scienceurn:http-www-brinckerhoff-org:-blog-2015-06-14-break-it-confrontational-thinking-in-computer-science2015-06-14T19:09:51Z2015-06-14T19:09:51ZJohn Clements
<p>So here I am grading another exam. This exam question asks students to imagine what would happen to an interpreter if environments were treated like stores. Then, it asks them to construct a program that would illustrate the difference.</p>
<p>They fail, completely.</p>
<p>(Okay, not completely.)</p>
<p>By and large, it’s pretty easy to characterize the basic failing: these students are unwilling to break the rules.</p>
<!-- more-->
<p>I feel like this idea has been hitting me over the head for a couple of months, now, so I’m going to write it down. Specifically, I see many areas of computer science where it’s important to engage in what I call “confrontational thinking.” Taking something that looks good, and poking holes in it to find out what’s wrong with it.</p>
<p>Is this what other people call “critical thinking”? I don’t think so. Associations are important, and I think that the term “critical thinking” now simply refers to a watery desire for students to somehow be more well-rounded and high-level thinkers. I’m thinking of something different.</p>
<p>For me, I think this skill is most closely affiliated with Math. Specifically, if you want to succeed in Math (and no, I don’t mean the ability to memorize and deploy the closed-form solution to quadratics), you need to be able to take a nice idea and bash it against the wall. Find counterexamples, think outside the box. Try to prove your professor wrong. All kinds of interesting things fall out when you disassemble the nice clean theorems that you’re given.</p>
<p>In programming, this may be even more important. In programming, after all, the artifacts are not theorems given to you by teachers (and proven by Euclid)—they’re programs you wrote yourself, and they’re probably jammed with bugs. If you can’t attack your program, and try to break it, you’re going to develop fragile artifacts that work only for the corner that your mind was stuck in.</p>
<p>In the classroom, this is how you learn. Students that patiently absorb all of the text on the board don’t appear (to me) to actually be learning anything; it’s those that are in your face—as long as they can clearly enunciate their questions—that are assembling knowledge.</p>
<p>I was reminded of this by watching one of Veritasium’s excellent youtube posts, this one on <a href="https://www.youtube.com/watch?v=vKA4w2O61Xo">discovering the rule that generates a sequence of numbers</a>. Excellent, I should say, except that I wanted to shout at the people in the video. Go take a look to see what I mean. These people are having a lot of trouble engaging in confrontational thinking.</p>
<p>Why do students have such trouble with this?</p>
<p>I think that one reason may be that we learn different kinds of things in different ways.</p>
<p>So, for instance, consider learning to walk. This is something we learn very early, long before we’re able to absorb complex instructions. We’re certainly partially hard-wired for this, but a big chunk of it is trial and error.</p>
<p>Here’s the point, though. Once we learn to walk, do we engage in confrontational thinking about the process? Heck no! Deliberately try to walk wrong, to see what happens? I’m pretty sure I can accurately guess what’s going to happen, and it’s probably going to involve bleeding and bandages.</p>
<p>For this kind of activity, confrontational thinking is not the best idea. Instead, we find the way that works, and we stick with it.</p>
<p>More generally, this is the way that we actually get things done in our lives. If every morning I decide to question the way that breakfast works—whether I can fry an egg without a pan, or whether the food needs to go in my mouth—I’m going to end up messy and frustrated.</p>
<p>For many of our students, I claim, programming is like this. After many painful episodes of trial and error, they’ve developed scars and bruises, and know of one narrow path that happens to work pretty well. Getting them to consider other paths is frightening and aversive. (Say, for instance, the parenthesized syntax of lisp-like languages.)</p>
<p>In fact, if you want to really go overboard, you can compare these two learning styles to the notions of conservatism and liberality. The conservative style gets the job done, using fewer resources and taking fewer risks. The liberal style involves self-doubt and failure, but is ultimately necessary in order to learn.</p>
<p>Hmm… when I put it that way, it sounds perfectly obvious.</p>
<p>Now, the only question is how to get the students to engage, and start questioning me.</p>my root password? oh sure, here it is.urn:http-www-brinckerhoff-org:-blog-2015-05-07-my-root-password-oh-sure-here-it-is2015-05-07T21:57:03Z2015-05-07T21:57:03ZJohn Clements
<p>So, I just bought a copy of Screenflow, an apparently reputable piece of screencasting software for the mac. They sent me a license code. Now it’s time to enter it. Here’s the window:</p>
<div class="figure"><img src="/img/screenflow-license-window.png" alt="" />
<p class="caption"></p></div>
<p>Hmm… says here all I need to do is… enter my admin password, and then the license code.</p>
<p>Wait… what?</p>
<p>Why in heaven’s name would Screenflow need to know my admin password here?</p>
<p>My <em>guess</em> is that it’s because it wants to put something in the keychain for me. That’s not a very comforting thought; it also means that it could delete things from my keychain, copy the whole thing, etc. etc.</p>
<p>This is a totally unacceptable piece of UI. I think it’s probably both Apple’s and Telestream’s fault. Really, though, I just paid $100 and now I have to decide whether to try to get my money back, or just take the chance that Telestream isn’t evil.</p>
<!-- more-->
<h2 id="the-larger-question">The Larger Question</h2>
<p>The more I think about this, though, the deeper it gets. Is there any realistic way to partition passwords into high-security and low-security? If I have a password manager, then clearly the password for my account there is pretty much my highest-security item; having that password allows someone access to all my bank accounts, etc. Compromising that would be a disaster.</p>
<p>But wait! If you have root on any machine that I use to access that password manager, then you can presumably install a keystroke logger that can observe me typing the password for that password manager (unless I use a hardware-based authentication mechanism), so all of those passwords are pretty much vital as well. I’m thinking specifically of the administrator password on my laptop.</p>
<p>Unfortunately, consumer OSes are pretty cavalier in their handling of administrator passwords. I obviously have no choice but to trust the OS itself in handling that password, but I really don’t want to trust any other application code in that way. However, there’s no reliable way for me to determine, given a window that asks for my password, whether it’s “from the OS” or not. Solving this would involve some fairly drastic steps. The one that comes to mind is having a special light—say, on the side of the keyboard—that indicates that the OS is asking me to enter my password. This would presumably be accompanied by some kind of full-screen takeover. I’m guessing that most OS designers would not find this appealing.</p>
<p>I’d buy it, though.</p>
<p>Does this make me a tinfoil-hat guy?</p>
<h3 id="post-scriptum">Post Scriptum</h3>
<p>In the end, I did get a refund from Telestream; it was prompt, and they convinced me that they have good business practices, even if their security model stinks.</p>Is teaching programming like teaching math?urn:http-www-brinckerhoff-org:-blog-2014-12-17-is-teaching-programming-like-teaching-math2014-12-17T14:13:02Z2014-12-17T14:13:02ZJohn Clements
<p>One of my children is in third grade. As part of a “back-to-school” night this year, I sat in a very small chair while a teacher explained to me the “Math Practices” identified as part of the new Common Core standards for math teaching.</p>
<p>Perhaps the small chair simply made me more receptive, taking me back to third grade myself, but as she ran down the list, I found myself thinking: “gosh, these are exactly the same skills that I want to impart to beginning programmers!”</p>
<p>Here’s the list of Math Practices, a.k.a. <a href="https://duckduckgo.com/l/?kh=-1&uddg=http%3A%2F%2Fwww.corestandards.org%2FMath%2FPractice%2F">“Standards for Mathematical Practice”</a>:</p>
<ol>
<li>Make sense of problems and persevere in solving them.</li>
<li>Reason abstractly and quantitatively.</li>
<li>Construct viable arguments and critique the reasoning of others.</li>
<li>Model with Mathematics.</li>
<li>Use appropriate tools strategically.</li>
<li>Attend to precision.</li>
<li>Look for and make use of structure.</li>
<li>Look for and express regularity in repeated reasoning.</li></ol>
<p>Holy Moley! Those are <em>incredibly</em> relevant in teaching programming. Furthermore, they sound like they were written by someone intimately familiar with the <a href="http://www.htdp.org">How To Design Programs</a> or <a href="http://www.bootstrapworld.org">Bootstrap</a> curricula. Indeed, in the remainder of my analysis, I’ll be referring specifically to the steps 1–4 of the design recipe proposed by HtDP (as, e.g., “step 2 of DR”).</p>
<p>Let’s take those apart, one by one:</p>
<!-- more-->
<ol>
<li>
<p><strong>Make sense of problems and persevere in solving them.</strong></p>
<p>This is really two things, but they’re both incredibly important in programming. The first one puts the emphasis first on understanding the problem. Don’t charge ahead and try to solve the problem (write the program) before you have some understanding of the problem. This can be clearly expressed by writing a purpose statement (part of step 2 of DR), and by designing data (step 1 of DR).</p>
<p>The second part of this—perseverance—is incredibly important. It’s not directly a step in solving the problem, but it’s one of a family of meta-skills that largely determines whether a student succeeds in an introductory programming class (erm, citation needed).</p></li>
<li>
<p><strong>Reason abstractly and quantitatively.</strong></p>
<p>Bouncing back and forth between the abstract and the quantitative is one of the key skills in programming. Indeed, a program represents a mapping from problem to solution for a large set of problems; the transition from the concrete to the abstract is the raison d’etre of programming itself.</p>
<p>Want to multiply one pair of numbers? use a calculator. Want to multiply seventy million pairs of numbers? write a program.</p>
<p>However, humans work best—and learn best—when we’re thinking about concrete, quantitative problems. That’s why step 3 of the design recipe requires students to come up with concrete examples of problem inputs, and the corresponding results. Without these concrete examples, students quickly get lost in trying to tackle all possible inputs, without being able to focus on concrete, quantitative inputs.</p></li>
<li>
<p><strong>Construct viable arguments and critique the reasoning of others.</strong></p>
<p>One of the key skills that programmers require is that of <em>understanding</em> programs. Learning to program without learning to read others’ programs is like learning to talk without knowing how to listen. It’s true that students see small examples of programs in textbooks and in class, but it’s also vital for students to see other students programs; learning to understand these will help them to see what’s missing in their own programs <sup><a href="#2014-12-17-is-teaching-programming-like-teaching-math-footnote-1-definition" name="2014-12-17-is-teaching-programming-like-teaching-math-footnote-1-return">1</a></sup> <sup><a href="#2014-12-17-is-teaching-programming-like-teaching-math-footnote-2-definition" name="2014-12-17-is-teaching-programming-like-teaching-math-footnote-2-return">2</a></sup> <sup><a href="#2014-12-17-is-teaching-programming-like-teaching-math-footnote-3-definition" name="2014-12-17-is-teaching-programming-like-teaching-math-footnote-3-return">3</a></sup> <sup><a href="#2014-12-17-is-teaching-programming-like-teaching-math-footnote-4-definition" name="2014-12-17-is-teaching-programming-like-teaching-math-footnote-4-return">4</a></sup>.</p>
<p>Also, programmers frequently engage in the activity of debugging. Okay, <em>extremely</em> frequently. The process of debugging is fundamentally one of <em>regarding one’s own program as a third party</em>. It’s clear to the programmer what they <em>meant</em> the program to do, but debugging it requires them to look at the program as if it were written by someone else, doing their best to peel off the lens of intention, and see what it actually, does, not what they meant it to do. They must then construct viable arguments as to why the program performs as it does, and how to correct it.</p>
<p>Debugging is a truly vital programming skill that is often not well taught.</p></li>
<li>
<p><strong>Model with Mathematics.</strong></p>
<p>“Model with Mathematics” is, more or less, another name for programming.</p>
<p>It’s not clear whether this adds anything to the conversation, but it seems clear that there’s more or less one hundred percent overlap between this “practice” and that of programming.</p></li>
<li>
<p><strong>Use appropriate tools strategically.</strong></p>
<p>Writing a program consists entirely in applying various functions and language constructs to a set of inputs.</p>
<p>In the first few weeks, these tools consist almost entirely of basic mathematical and graphical functions: plus, times, rectangle, and the like.</p>
<p>Later, students can bring to bear their knowledge of the “tools” of program templates (step 4 in the design recipe) to organize programs that operate on more complex forms of data. This is still in the “hand-holding” phase of programming.</p>
<p>Still later, students will learn about more sophisticated programming “tools”—divide and conquer forms of generative recursion, standard iteration functions (map, filter, foldl), and optimization techniques such as memoization. These tools pop instantly to the mind of a seasoned programmer, just as a woodworker might immediately identify the rabbet plane that will create the desired shape without difficulty.</p></li>
<li>
<p><strong>Attend to precision.</strong></p>
<p>Precision arrives somewhat later for programmers than it does for students of math. In the first ten or twenty weeks of student programming, programs tend to be entirely right or catastrophically wrong, especially if they’re following the steps of the design recipe, and using data definitions supplied to them.</p>
<p>Later, though, precision takes on an increasing importance. Programming is largely algebraic—how to combine operators and language forms to build a program—and the “precision” that is most often missing is that of corner cases, and unexpected combinations of data. “Attending to precision” in these cases consists in developing test cases that carefully cover the space of possible inputs.</p></li>
<li>
<p><strong>Look for and make use of structure.</strong></p>
<p>Making use of structure is in some ways the fundamental job of a programmer. The programmer must—before even beginning to write the program—decide how to model the data of the problem as values in some programming language. This is step 1 of the design recipe, and for the first five or six weeks of programming, students can’t be expected to design their own data.</p>
<p>In the next five or six weeks, students develop the ability to choose simple structures to represent well-understood data.</p>
<p>Finally, students move on to tackling problems where there is no single best way to model the data. In these cases, the best model may depend on operational constraints, or data volume, or any number of other criteria. Indeed, the entire fields of databases and data science may be considered to be an expression of this practice.</p></li>
<li>
<p><strong>Look for and express regularity in repeated reasoning.</strong></p>
<p>Yeah, that’s abstraction. Important in programming.</p></li></ol>
<hr />
<p>Okay, so that’s it. I hope it’s clear at this point that</p>
<p>Teaching math is a lot like teaching programming.</p>
<p>For more, take a look at Felleisen & Krishnamurthi, “Why Computer Science Doesn’t Matter,” <sup><a href="#2014-12-17-is-teaching-programming-like-teaching-math-footnote-5-definition" name="2014-12-17-is-teaching-programming-like-teaching-math-footnote-5-return">5</a></sup>.</p>
<div class="footnotes">
<ol>
<li id="2014-12-17-is-teaching-programming-like-teaching-math-footnote-1-definition" class="footnote-definition">
<p>Kulkarni, Chinmay, Steven P. Dow, and Scott R. Klemmer. “Early and repeated exposure to examples improves creative work.” Design Thinking Research. Springer International Publishing, 2014. 49–62. <a href="http://link.springer.com/chapter/10.1007/978-3-319-01303-9_4">http://link.springer.com/chapter/10.1007/978–3–319–01303–9_4</a> <a href="#2014-12-17-is-teaching-programming-like-teaching-math-footnote-1-return">↩</a></p></li>
<li id="2014-12-17-is-teaching-programming-like-teaching-math-footnote-2-definition" class="footnote-definition">
<p>Politz, Joe Gibbs, Shriram Krishnamurthi, and Kathi Fisler. “In-flow peer-review of tests in test-first programming.” Proceedings of the tenth annual conference on International computing education research. ACM, 2014. <a href="http://dl.acm.org/citation.cfm?id=2632347">http://dl.acm.org/citation.cfm?id=2632347</a> <a href="#2014-12-17-is-teaching-programming-like-teaching-math-footnote-2-return">↩</a></p></li>
<li id="2014-12-17-is-teaching-programming-like-teaching-math-footnote-3-definition" class="footnote-definition">
<p>Hundhausen, Christopher D., Anukrati Agrawal, and Pawan Agarwal. “Talking about code: Integrating pedagogical code reviews into early computing courses.” ACM Transactions on Computing Education (TOCE) 13.3 (2013): 14. <a href="http://dl.acm.org/citation.cfm?id=2499951">http://dl.acm.org/citation.cfm?id=2499951</a> <a href="#2014-12-17-is-teaching-programming-like-teaching-math-footnote-3-return">↩</a></p></li>
<li id="2014-12-17-is-teaching-programming-like-teaching-math-footnote-4-definition" class="footnote-definition">
<p>Sondergaard, Harald. “Learning from and with peers: the different roles of student peer reviewing.” ACM SIGCSE Bulletin. Vol. 41. No. 3. ACM, 2009. <a href="http://dl.acm.org/citation.cfm?id=1562893">http://dl.acm.org/citation.cfm?id=1562893</a> <a href="#2014-12-17-is-teaching-programming-like-teaching-math-footnote-4-return">↩</a></p></li>
<li id="2014-12-17-is-teaching-programming-like-teaching-math-footnote-5-definition" class="footnote-definition">
<p>Felleisen, Matthias, and Shriram Krishnamurthi. “Viewpoint Why computer science doesn’t matter.” Communications of the ACM 52.7 (2009): 37–40. <a href="http://dl.acm.org/citation.cfm?id=1538803">http://dl.acm.org/citation.cfm?id=1538803</a> <a href="#2014-12-17-is-teaching-programming-like-teaching-math-footnote-5-return">↩</a></p></li></ol></div>DWIM vs. Small Semantic Coreurn:http-www-brinckerhoff-org:-blog-2014-10-23-dwim-vs-small-semantic-core2014-10-23T17:56:10Z2014-10-23T17:56:10ZJohn Clements
<p>So, I’d like to do some statistical analysis. I hear that R is really good at this. Let’s download it and take a look.</p>
<p>(Ten minutes later)</p>
<p>AAAHHH! MY EYES! THEY’RE BLEEDING!</p>
<p>What about Matlab? It’s the same story.<sup><a href="#2014-10-23-dwim-vs-small-semantic-core-footnote-1-definition" name="2014-10-23-dwim-vs-small-semantic-core-footnote-1-return">1</a></sup> As a programming languages person, these languages make me … well, angry.</p>
<p>Why?</p>
<p>Well, after thinking about this for a while, it seems to me that what I hate most about these languages is their complete lack of a small semantic core.</p>
<p>Take a language like Racket, JavaScript, Java, or C— these languages don’t have a heck of a lot in common, but they share</p>
<p>…</p>
<p>is this all just library design? Most of the things I really hate can easily be constructed in any dynamic library through a suitable application of</p>
<p>Terrible Library Design (tm)</p>
<p>… except that when it applies to things like vector dereference, it feels like fairly ‘core’ syntax.</p>
<p>…</p>
<p>Example time! First, R does this crazy thing in distinguishing logical from numeric vectors.</p>
<div class="brush: R">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="o">></span> <span class="n">a</span>
<span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="s">"a"</span> <span class="s">"b"</span> <span class="s">"c"</span> <span class="s">"d"</span>
<span class="o">></span> <span class="n">a</span><span class="p">[</span><span class="nf">c</span><span class="p">(</span><span class="m">2</span><span class="p">,</span><span class="m">4</span><span class="p">,</span><span class="m">3</span><span class="p">)]</span>
<span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="s">"b"</span> <span class="s">"d"</span> <span class="s">"c"</span>
<span class="o">></span> <span class="n">a</span><span class="p">[</span><span class="nf">c</span><span class="p">(</span><span class="kc">FALSE</span><span class="p">,</span><span class="kc">TRUE</span><span class="p">)]</span>
<span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="s">"b"</span> <span class="s">"d"</span>
</pre></div></td></tr></tbody></table></div>
</div>
<p>In the first of these two array derefs, we’re using the indices from the vector to decide what elements of <code>a</code> to take. In the second case, though, the index expression is a ‘logical vector’ and is therefore tiled to the length of the original one, and used to decide whether to take the corresponding element.</p>
<p>If you imagine this as part of a language semantics, you’d see this horrible side-condition attached to these rules, where array deref’ing works in totally different ways depending on the kind of argument it gets.</p>
<p>To say nothing of the silent tiling, which seems like an open invitation to horrible bugs.</p>
<p>But wait, we can compound this problem with some nasty coercion:</p>
<div class="brush: R">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal">1</span>
<span class="normal">2</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="o">></span> <span class="n">a</span><span class="p">[</span><span class="nf">c</span><span class="p">(</span><span class="m">4</span><span class="p">,</span><span class="nf">c</span><span class="p">(</span><span class="kc">FALSE</span><span class="p">,</span><span class="kc">TRUE</span><span class="p">,</span><span class="kc">TRUE</span><span class="p">))]</span>
<span class="p">[</span><span class="m">1</span><span class="p">]</span> <span class="s">"d"</span> <span class="s">"a"</span> <span class="s">"a"</span>
</pre></div></td></tr></tbody></table></div>
</div>
<p>What on earth is going on here? First of all, vectors get silently flattened, so that <code>c(3,c(4,5))</code> is the same as <code>c(3,4,5)</code> — ugh — but then, the logical values are coerced into numeric ones, so the index vector that’s produced is actually <code>c(4,0,1,1)</code>, which is then used to index the vector <code>a</code>. But why are there only three values? Oh, well, there’s no index 0, so let’s just skip that one, shall we?</p>
<p>Honestly, I guess the real problem is in thinking of something like R as a programming language; it’s not. It’s a statistical analysis tool, with a rich text-based interface. After all, would I get upset if Photoshop used ‘b’ for blur and ‘s’ for sharpen and I couldn’t nest them the way that I wanted, using parentheses? Probably not.</p>
<p>And finally: apologies for everything I’ve written. I’ve used R for about fifteen minutes, and this piece is really just me blowing off a small amount of steam. Not well written, not well thought-out. Meh.</p>
<div class="footnotes">
<ol>
<li id="2014-10-23-dwim-vs-small-semantic-core-footnote-1-definition" class="footnote-definition">
<p>Actually, maybe not; I spoke with a friend yesterday, and I get the impression that Matlab may not be as horrible as R, here. <a href="#2014-10-23-dwim-vs-small-semantic-core-footnote-1-return">↩</a></p></li></ol></div>Macros: more important in low-level languages?urn:http-www-brinckerhoff-org:-blog-2014-06-25-macros-more-important-in-low-level-languages2014-06-25T18:43:37Z2014-06-25T18:43:37ZJohn Clements
<p>Macros are a wonderful thing. A hygienic macro system puts language extensions within the reach of non-compiler-hackers.</p>
<p>However, to date, most modern, hygienic macro systems are associated with languages like Scheme and Racket that are quite high-level. My claim is that macros are probably much more useful in <em>low-level</em> languages. Here’s why:</p>
<!-- more-->
<h1 id="the-cost-of-abstraction">The cost of abstraction</h1>
<p>In high-level languages, programmers are not generally concerned about the cost of abstractions—for instance, function calls. If I have six blocks of similar code, I can probably design a function that accomplishes all six of them. In low-level languages, though, this may not be acceptable from a performance standpoint.</p>
<p>First of all, these languages generally lack tail-calling, so they always always allocate on function calls. Some (much?) of this cost can be ameliorated by inlining, which leads to:</p>
<p>Second of all, even in the presence of inlining, there are often places where the small reorganization required in order to make a function abstraction fit a bunch of similar pieces of code incurs a penalty in the sense that additional allocation may be necessary in order to organize things in a common format.</p>
<p>For both of these reasons, then, macros are more attractive; they allow you to abstract over syntax without incurring these penalties.</p>
<h1 id="the-lack-of-syntactic-uniformity">The lack of syntactic uniformity</h1>
<p>In functional languages,</p>
<ul>
<li>nearly everything is an expression, and</li>
<li>functions abstract over expressions.</li></ul>
<p>These two combine to form a nearly universal means of abstraction for similar pieces of code.</p>
<p>In many other languages, though, there are lots of things that are <em>not</em> expressions. Function definitions may not be expressions, annotations and modules and globals won’t be expressions, classes and trait declarations aren’t expressions, etc. Functions can typically only be used to abstract over expressions, and sequences of statements.</p>
<p>This means that in these other languages, abstracting over these other pieces can be impossible. I can definitely imagine wanting, for instance, a tidy way to add a hidden argument to a function, or to add a default trait implementation, or to hide details of a class system boilerplate; all of these are plausible with macros.</p>
<h1 id="done">Done</h1>
<p>So: add a modern, hygienic macro system to your new systems programming language. Hello, <a href="http://www.rust-lang.org">Rust</a>!</p>Too Elegant For Septemberurn:http-www-brinckerhoff-org:-blog-2013-04-04-too-elegant-for-september2013-04-04T21:18:00Z2013-04-04T21:18:00ZJohn Clements
<p>Being on sabbatical has given me a bit of experience with other systems and languages. Also, my kids are now old enough to “mess around” with programming. Learning from both of these, I’d like to hazard a bit of HtDP heresy: students should learn <code>for i = 1 to 10</code> before they learn</p>
<div class="brush: racket">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="p">(</span><span class="n">sum</span><span class="w"> </span><span class="n">lon</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket/private/letstx-scheme..rkt)._cond))" style="color: inherit">cond</a></span><span class="w"> </span><span class="p">[(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket/list..rkt)._empty~3f))" style="color: inherit">empty?</a></span><span class="w"> </span><span class="n">lon</span><span class="p">)</span><span class="w"> </span><span class="mi">0</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="k"><a href="http://docs.racket-lang.org/reference/if.html#(form._((lib._racket/private/letstx-scheme..rkt)._else))" style="color: inherit">else</a></span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._+))" style="color: inherit">+</a></span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket/list..rkt)._first))" style="color: inherit">first</a></span><span class="w"> </span><span class="n">lon</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="n">sum</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket/list..rkt)._rest))" style="color: inherit">rest</a></span><span class="w"> </span><span class="n">lon</span><span class="p">)))]))</span><span class="w"></span>
</pre></div></td></tr></tbody></table></div>
</div>
<p>To many of you, this may seem obvious. I’m not writing to you. Or maybe you folks can just read along and nod sagely.</p>
<p>HtDP takes this small and very lovely thing—recursive traversals over inductively defined data—and shows how it covers a huge piece of real estate. Really, if students could just understand how to write this class of programs effectively, they would have a <em>vastly</em> easier time with much of the rest of their programming careers, to say nothing of the remainder of their undergraduate tenure. Throw a few twists in there—a bit of mutation for efficiency, some memoization, some dynamic programming—and you’re pretty much done with the programming part of your first four years.</p>
<p>The sad thing is that many, many students make it through an entire four-year curriculum without ever really figuring out how to write a simple recursive traversal of an inductively defined data structure. This makes professors sad.</p>
<p>Among the Very Simple applications of this nice idea is that of “indexes.” That is, the natural numbers can be regarded as an inductively defined set, where a natural number is either 0 or the successor of a natural number. This allows you to regard any kind of indexing loop as simply a special case of … a recursive traversal of an inductively defined data structure.</p>
<p>So here’s the problem: in September, you face a bunch of bright-eyed, enthusiastic, deeply forgiving first-year college students. And you give them the recursive traversal of the inductively defined data structure. A very small number of them get it, and they’re off to the races. The rest of them struggle, and struggle, and finally get their teammates to help them write the code, and really wish they’d taken some other class.</p>
<h3 id="nb-the-rest-of-this-makes-less-sense-even-to-me-not-finished">NB: the rest of this makes less sense… even to me. Not finished.</h3>
<p>However, another big part of the problem is … well, <a href="http://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/">monads are like burritos</a>.</p>
<p>Let me take a step back.</p>
<p>The notion of repeated action is a visceral and easily-understood one. Here’s what I mean. “A human can multiply a pair of 32-bit integers in about a minute. A computer can multiply 32-bit integers at a rate of several billion per second, or about a hundred billion times as fast as a person.” That’s an easily-understood claim: we understand what it means to the same thing a whole bunch of times really fast.</p>
<p>So, when I write</p>
<p><code>for i=[1..100] multiply_two_numbers();</code></p>
<p>It’s pretty easy to understand that I’m doing something one hundred times.</p>Embedding Rust in Racketurn:http-www-brinckerhoff-org:-blog-2013-03-29-embedding-rust-in-racket2013-03-29T21:18:00Z2013-03-29T21:18:00ZJohn Clements
<p>Is this post a thinly disguised ripoff of <a href="http://brson.github.com/2013/03/10/embedding-rust-in-ruby/">Brian Anderson’s post about embedding Rust in Ruby</a>? Why yes. Yes it is.</p>
<p>Okay, let me start with a little background. Rust is a magnificent language that comes from Mozilla; it’s targeted at programmers who want</p>
<ul>
<li>high and predictable performance,</li>
<li>control over memory layout,</li>
<li>good support for concurrency, and</li>
<li>safety.</li></ul>
<p>I think the <a href="http://www.mozilla.org/en-US/research/projects/#rust">Mozilla Research homepage</a> is probably the best place to start learning about Rust.</p>
<p>To be honest, though, I’m probably flattering myself if I think that this blog post is being read by anyone who doesn’t already know lots about Rust.</p>
<p>One of the key requirements of a language like Rust is that it be embeddable; that is, it should be possible to call Rust code from another language just as it’s possible to call C code from another language.</p>
<p>This is now possible.</p>
<p>To illustrate this, Brian Anderson posted a lovely example of embedding Rust in Ruby. But of course, embedding Rust in Ruby is pretty much exactly the same as embedding Rust in any other language.</p>
<p>Say, for instance, <a href="http://www.racket-lang.org/">Racket</a>.</p>
<p>So, without further ado, here’s the setup. You just happen to have a small web app written in Racket that performs a Gaussian Blur. You decide to optimize the performance by porting your code to Rust. Then you want to plug your Rust code into your Racket application. Done! <a href="https://github.com/jbclements/rustyracketdemo">Here’s the github repo that contains all of the code</a>.</p>
<p>Let’s see that again in slow motion.</p>
<p>First, here’s the gaussian blur function, written in Racket. We’re going to stick with a grayscale image. It works fine in color, but the code is just that much harder to read.</p>
<div class="brush: racket">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="c1">;; the gaussian filter used in the racket blur.</span><span class="w"></span>
<span class="c1">;; boosted center value by 1/1000 to make sure that whites stay white.</span><span class="w"></span>
<span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket/private/list..rkt)._filter))" style="color: inherit">filter</a></span><span class="w"> </span><span class="o">'</span><span class="p">[[</span><span class="mf">0.011</span><span class="w"> </span><span class="mf">0.084</span><span class="w"> </span><span class="mf">0.011</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mf">0.084</span><span class="w"> </span><span class="mf">0.620</span><span class="w"> </span><span class="mf">0.084</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mf">0.011</span><span class="w"> </span><span class="mf">0.084</span><span class="w"> </span><span class="mf">0.011</span><span class="p">]])</span><span class="w"></span>
<span class="c1">;; racket-blur: blur the image using the gaussian filter</span><span class="w"></span>
<span class="c1">;; number number list-of-bytes -> vector-of-bytes</span><span class="w"></span>
<span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="p">(</span><span class="n">racket-blur</span><span class="w"> </span><span class="n">width</span><span class="w"> </span><span class="n">height</span><span class="w"> </span><span class="n">data</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">data-vec</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._list-~3evector))" style="color: inherit">list->vector</a></span><span class="w"> </span><span class="n">data</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="c1">;; ij->offset : compute the offset of the pixel data within the buffer</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="p">(</span><span class="n">ij->offset</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._+))" style="color: inherit">+</a></span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._*))" style="color: inherit">*</a></span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="n">width</span><span class="p">)))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">bytes-len</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._*))" style="color: inherit">*</a></span><span class="w"> </span><span class="n">width</span><span class="w"> </span><span class="n">height</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">new-bytes</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._make-vector))" style="color: inherit">make-vector</a></span><span class="w"> </span><span class="n">bytes-len</span><span class="w"> </span><span class="mi">0</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">filter-x</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._length))" style="color: inherit">length</a></span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._car))" style="color: inherit">car</a></span><span class="w"> </span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket/private/list..rkt)._filter))" style="color: inherit">filter</a></span><span class="p">)))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">filter-y</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._length))" style="color: inherit">length</a></span><span class="w"> </span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket/private/list..rkt)._filter))" style="color: inherit">filter</a></span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">offset-x</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._/))" style="color: inherit">/</a></span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._sub1))" style="color: inherit">sub1</a></span><span class="w"> </span><span class="n">filter-x</span><span class="p">)</span><span class="w"> </span><span class="mi">2</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">offset-y</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._/))" style="color: inherit">/</a></span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._sub1))" style="color: inherit">sub1</a></span><span class="w"> </span><span class="n">filter-y</span><span class="p">)</span><span class="w"> </span><span class="mi">2</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="c1">;; compute the filtered byte array</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/for.html#(form._((lib._racket/private/base..rkt)._for*))" style="color: inherit">for*</a></span><span class="w"> </span><span class="p">([</span><span class="n">x</span><span class="w"> </span><span class="n">width</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="n">y</span><span class="w"> </span><span class="n">height</span><span class="p">])</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">new-val</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/for.html#(form._((lib._racket/private/base..rkt)._for*/fold))" style="color: inherit">for*/fold</a></span><span class="w"> </span><span class="p">([</span><span class="n">sum</span><span class="w"> </span><span class="mf">0.0</span><span class="p">])</span><span class="w"></span>
<span class="w"> </span><span class="p">([</span><span class="n">dx</span><span class="w"> </span><span class="n">filter-x</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="n">dy</span><span class="w"> </span><span class="n">filter-y</span><span class="p">])</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">sample-x</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._modulo))" style="color: inherit">modulo</a></span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._+))" style="color: inherit">+</a></span><span class="w"> </span><span class="n">dx</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._-))" style="color: inherit">-</a></span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">offset-x</span><span class="p">))</span><span class="w"> </span><span class="n">width</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">sample-y</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._modulo))" style="color: inherit">modulo</a></span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._+))" style="color: inherit">+</a></span><span class="w"> </span><span class="n">dy</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._-))" style="color: inherit">-</a></span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="n">offset-y</span><span class="p">))</span><span class="w"> </span><span class="n">height</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">sample-value</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector-ref))" style="color: inherit">vector-ref</a></span><span class="w"> </span><span class="n">data-vec</span><span class="w"> </span><span class="p">(</span><span class="n">ij->offset</span><span class="w"> </span><span class="n">sample-x</span><span class="w"> </span><span class="n">sample-y</span><span class="p">)))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">weight</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._list-ref))" style="color: inherit">list-ref</a></span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((quote._~23~25kernel)._list-ref))" style="color: inherit">list-ref</a></span><span class="w"> </span><span class="nb"><a href="http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket/private/list..rkt)._filter))" style="color: inherit">filter</a></span><span class="w"> </span><span class="n">dy</span><span class="p">)</span><span class="w"> </span><span class="n">dx</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._+))" style="color: inherit">+</a></span><span class="w"> </span><span class="n">sum</span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/generic-numbers.html#(def._((quote._~23~25kernel)._*))" style="color: inherit">*</a></span><span class="w"> </span><span class="n">weight</span><span class="w"> </span><span class="n">sample-value</span><span class="p">))))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector-set!))" style="color: inherit">vector-set!</a></span><span class="w"> </span><span class="n">new-bytes</span><span class="w"> </span><span class="p">(</span><span class="n">ij->offset</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="n">new-val</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/vectors.html#(def._((quote._~23~25kernel)._vector-~3elist))" style="color: inherit">vector->list</a></span><span class="w"> </span><span class="n">new-bytes</span><span class="p">))</span><span class="w"></span>
</pre></div></td></tr></tbody></table></div>
</div>
<p>Suppose we want to rewrite that in Rust. Here’s what it might look like:</p>
<div class="brush: rust">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="k">fn</span> <span class="nf">blur_rust</span><span class="p">(</span><span class="n">width</span>: <span class="nc">uint</span><span class="p">,</span><span class="w"> </span><span class="n">height</span>: <span class="nc">uint</span><span class="p">,</span><span class="w"> </span><span class="n">data</span>: <span class="kp">&</span><span class="p">[</span><span class="kt">u8</span><span class="p">])</span><span class="w"> </span>-> <span class="o">~</span><span class="p">[</span><span class="kt">u8</span><span class="p">]</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">filter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[[</span><span class="mf">0.011</span><span class="p">,</span><span class="w"> </span><span class="mf">0.084</span><span class="p">,</span><span class="w"> </span><span class="mf">0.011</span><span class="p">],</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mf">0.084</span><span class="p">,</span><span class="w"> </span><span class="mf">0.620</span><span class="p">,</span><span class="w"> </span><span class="mf">0.084</span><span class="p">],</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mf">0.011</span><span class="p">,</span><span class="w"> </span><span class="mf">0.084</span><span class="p">,</span><span class="w"> </span><span class="mf">0.011</span><span class="p">]];</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">newdata</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">~</span><span class="p">[];</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">uint</span>::<span class="n">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">height</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="n">y</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">uint</span>::<span class="n">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">width</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="n">x</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">new_value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">uint</span>::<span class="n">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">filter</span><span class="p">.</span><span class="n">len</span><span class="p">())</span><span class="w"> </span><span class="o">|</span><span class="n">yy</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">uint</span>::<span class="n">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">filter</span><span class="p">.</span><span class="n">len</span><span class="p">())</span><span class="w"> </span><span class="o">|</span><span class="n">xx</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">x_sample</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">filter</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">xx</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">y_sample</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">filter</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">yy</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">sample_value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">data</span><span class="p">[</span><span class="n">width</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="n">y_sample</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">height</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">x_sample</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">width</span><span class="p">)];</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">sample_value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">sample_value</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">float</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">weight</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">filter</span><span class="p">[</span><span class="n">yy</span><span class="p">][</span><span class="n">xx</span><span class="p">];</span><span class="w"></span>
<span class="w"> </span><span class="n">new_value</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">sample_value</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">weight</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">newdata</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">new_value</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">u8</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">newdata</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div></td></tr></tbody></table></div>
</div>
<p>Pretty similar. Of course, it uses curly braces, so it runs about three times faster…</p>
<p>So: what kind of glue code is necessary to link the Rust code to the Racket code? Not a lot. On the Rust side, we need to create a pointer to the C data, then copy the result back into the source buffer when we’re done with the blur:</p>
<div class="brush: rust">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="cp">#[no_mangle]</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">extern</span><span class="w"> </span><span class="k">fn</span> <span class="nf">blur</span><span class="p">(</span><span class="n">width</span>: <span class="nc">c_uint</span><span class="p">,</span><span class="w"> </span><span class="n">height</span>: <span class="nc">c_uint</span><span class="p">,</span><span class="w"> </span><span class="n">data</span>: <span class="o">*</span><span class="k">mut</span><span class="w"> </span><span class="kt">u8</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">width</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">width</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">uint</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">height</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">height</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">uint</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kr">do</span><span class="w"> </span><span class="n">vec</span>::<span class="n">raw</span>::<span class="n">mut_buf_as_slice</span><span class="p">(</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">width</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">height</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="n">data</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">out_data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">blur_rust</span><span class="p">(</span><span class="n">width</span><span class="p">,</span><span class="w"> </span><span class="n">height</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">vec</span>::<span class="n">raw</span>::<span class="n">copy_memory</span><span class="p">(</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">out_data</span><span class="p">,</span><span class="w"> </span><span class="n">width</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">height</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div></td></tr></tbody></table></div>
</div>
<p>On the Racket side, it’s just a question of making an ffi call, which is super-concise:</p>
<div class="brush: racket">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="c1">;; link to the rust library:</span><span class="w"></span>
<span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">rust-lib</span><span class="w"> </span><span class="p">(</span><span class="n"><a href="http://docs.racket-lang.org/foreign/Loading_Foreign_Libraries.html#(def._((lib._ffi/unsafe..rkt)._ffi-lib))" style="color: inherit">ffi-lib</a></span><span class="w"> </span><span class="p">(</span><span class="nb"><a href="http://docs.racket-lang.org/reference/Manipulating_Paths.html#(def._((quote._~23~25kernel)._build-path))" style="color: inherit">build-path</a></span><span class="w"> </span><span class="n">here</span><span class="w"> </span><span class="s2">"libblur-68a2c114141ca-0.0"</span><span class="p">)))</span><span class="w"></span>
<span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">rust-blur-fun</span><span class="w"> </span><span class="p">(</span><span class="n"><a href="http://docs.racket-lang.org/foreign/Loading_Foreign_Libraries.html#(def._((lib._ffi/unsafe..rkt)._get-ffi-obj))" style="color: inherit">get-ffi-obj</a></span><span class="w"> </span><span class="s2">"blur"</span><span class="w"> </span><span class="n">rust-lib</span><span class="w"> </span><span class="p">(</span><span class="n"><a href="http://docs.racket-lang.org/foreign/foreign_procedures.html#(form._((lib._ffi/unsafe..rkt).__fun))" style="color: inherit">_fun</a></span><span class="w"> </span><span class="n"><a href="http://docs.racket-lang.org/foreign/Numeric_Types.html#(def._((lib._ffi/unsafe..rkt).__uint))" style="color: inherit">_uint</a></span><span class="w"> </span><span class="n"><a href="http://docs.racket-lang.org/foreign/Numeric_Types.html#(def._((lib._ffi/unsafe..rkt).__uint))" style="color: inherit">_uint</a></span><span class="w"> </span><span class="n">_cvector</span><span class="w"> </span><span class="k"><a href="http://docs.racket-lang.org/reference/function-contracts.html#(form._((lib._racket/contract/base..rkt)._-~3e))" style="color: inherit">-></a></span><span class="w"> </span><span class="n"><a href="http://docs.racket-lang.org/foreign/Other_Atomic_Types.html#(def._((quote._~23~25foreign).__void))" style="color: inherit">_void</a></span><span class="p">)))</span><span class="w"></span>
<span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="p">(</span><span class="n">rust-blur</span><span class="w"> </span><span class="n">width</span><span class="w"> </span><span class="n">height</span><span class="w"> </span><span class="n">data</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="k"><a href="http://docs.racket-lang.org/reference/define.html#(form._((lib._racket/private/base..rkt)._define))" style="color: inherit">define</a></span><span class="w"> </span><span class="n">cvec</span><span class="w"> </span><span class="p">(</span><span class="n">list->cvector</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="n"><a href="http://docs.racket-lang.org/foreign/Numeric_Types.html#(def._((lib._ffi/unsafe..rkt).__byte))" style="color: inherit">_byte</a></span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="n">rust-blur-fun</span><span class="w"> </span><span class="n">width</span><span class="w"> </span><span class="n">height</span><span class="w"> </span><span class="n">cvec</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="n">cvector->list</span><span class="w"> </span><span class="n">cvec</span><span class="p">))</span><span class="w"></span>
</pre></div></td></tr></tbody></table></div>
</div>
<p>And away you go!</p>
<p>I’ve got this code running live at FIXME. What’s that you say? You can’t seem to find FIXME?</p>Random Code 9: Perlurn:http-www-brinckerhoff-org:-blog-2012-04-23-random-code-9-perl2012-04-23T14:28:00Z2012-04-23T14:28:00ZJohn Clements
<div class="brush: perl">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="c1">#</span>
<span class="c1"># Globals:</span>
<span class="c1">#</span>
<span class="c1"># Regex to match balanced [brackets]. See Friedl's</span>
<span class="c1"># "Mastering Regular Expressions", 2nd Ed., pp. 328-331.</span>
<span class="k">my</span> <span class="nv">$g_nested_brackets</span><span class="p">;</span>
<span class="nv">$g_nested_brackets</span> <span class="o">=</span> <span class="sx">qr{</span>
<span class="sx"> (?> # Atomic matching</span>
<span class="sx"> [^\[\]]+ # Anything other than brackets</span>
<span class="sx"> | </span>
<span class="sx"> \[</span>
<span class="sx"> (??{ $g_nested_brackets }) # Recursive set of nested brackets</span>
<span class="sx"> \]</span>
<span class="sx"> )*</span>
<span class="sx">}</span><span class="n">x</span><span class="p">;</span>
<span class="c1"># Table of hash values for escaped characters:</span>
<span class="k">my</span> <span class="nv">%g_escape_table</span><span class="p">;</span>
<span class="k">foreach</span> <span class="k">my</span> <span class="nv">$char</span> <span class="p">(</span><span class="nb">split</span> <span class="sr">//</span><span class="p">,</span> <span class="s">'\\`*_{}[]()>#+-.!'</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$g_escape_table</span><span class="p">{</span><span class="nv">$char</span><span class="p">}</span> <span class="o">=</span> <span class="n">md5_hex</span><span class="p">(</span><span class="nv">$char</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1"># Global hashes, used by various utility routines</span>
<span class="k">my</span> <span class="nv">%g_urls</span><span class="p">;</span>
<span class="k">my</span> <span class="nv">%g_titles</span><span class="p">;</span>
<span class="k">my</span> <span class="nv">%g_html_blocks</span><span class="p">;</span>
<span class="c1"># Used to track when we're inside an ordered or unordered list</span>
<span class="c1"># (see _ProcessListItems() for details):</span>
<span class="k">my</span> <span class="nv">$g_list_level</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="c1">#### Blosxom plug-in interface ##########################################</span>
<span class="c1"># Set $g_blosxom_use_meta to 1 to use Blosxom's meta plug-in to determine</span>
<span class="c1"># which posts Markdown should process, using a "meta-markup: markdown"</span>
<span class="c1"># header. If it's set to 0 (the default), Markdown will process all</span>
<span class="c1"># entries.</span>
<span class="k">my</span> <span class="nv">$g_blosxom_use_meta</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">sub</span> <span class="nf">start</span> <span class="p">{</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span>
<span class="k">sub</span> <span class="nf">story</span> <span class="p">{</span>
<span class="k">my</span><span class="p">(</span><span class="nv">$pkg</span><span class="p">,</span> <span class="nv">$path</span><span class="p">,</span> <span class="nv">$filename</span><span class="p">,</span> <span class="nv">$story_ref</span><span class="p">,</span> <span class="nv">$title_ref</span><span class="p">,</span> <span class="nv">$body_ref</span><span class="p">)</span> <span class="o">=</span> <span class="nv">@_</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span> <span class="p">(</span><span class="o">!</span> <span class="nv">$g_blosxom_use_meta</span><span class="p">)</span> <span class="ow">or</span>
<span class="p">(</span><span class="nb">defined</span><span class="p">(</span><span class="nv">$</span><span class="nn">meta::</span><span class="nv">markup</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="nv">$</span><span class="nn">meta::</span><span class="nv">markup</span> <span class="o">=~</span><span class="sr"> /^\s*markdown\s*$/i</span><span class="p">))</span>
<span class="p">){</span>
<span class="nv">$$body_ref</span> <span class="o">=</span> <span class="n">Markdown</span><span class="p">(</span><span class="nv">$$body_ref</span><span class="p">);</span>
<span class="p">}</span>
<span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</pre></div></td></tr></tbody></table></div>
</div>
<!-- more-->
<p>I’m a bit surprised that Perl is so low on the list of common languages in github. I’m guessing this is because people tend to use Perl for small projects, and not for large ones.</p>
<p>This impression is bolstered by the most-forked Perl project on github, Gitolite, which is not a lot of code. Actually, it’s more than I thought—it turns out that Perl files can end with ".pl" <em>or</em> ".pm", silly me.</p>
<p>Okay, more later.</p>"Project 2 Testing"urn:http-www-brinckerhoff-org:-blog-2012-04-17-project-2-testing2012-04-18T00:59:00Z2012-04-18T00:59:00ZJohn Clements
<p>{% gist 2411008 %}</p>
<p>{% gist 2411005 %}</p>
<p>{% gist 2411004 %}</p>
<p>{% gist 2411002 %}</p>
<p>{% gist 2410993 %}</p>
<p>{% gist 2410918 %}</p>
<p>{% gist 2410916 %}</p>
<p>{% gist 2410910 %}</p>
<p>{% gist 2410909 %}</p>
<p>{% gist 2410908 %}</p>
<p>{% gist 2410905 %}</p>
<p>{% gist 2410904 %}</p>
<p>{% gist 2410899 %}</p>
<p>{% gist 2410889 %}</p>
<p>{% gist 2410886 %}</p>
<p>{% gist 2410882 %}</p>
<p>{% gist 2410860 %}</p>
<p>{% gist 2410856 %}</p>random code 8: urrggghurn:http-www-brinckerhoff-org:-blog-2012-04-13-random-code-8-urrgggh2012-04-13T20:03:00Z2012-04-13T20:03:00ZJohn Clements
<div class="brush: php">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="cp"><?php</span>
<span class="k">namespace</span> <span class="nx">Symfony\Component\Form\Tests\Extension\Core\Type</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\Form\FormError</span><span class="p">;</span>
<span class="k">class</span> <span class="nc">DateTimeTypeTest</span> <span class="k">extends</span> <span class="nx">LocalizedTestCase</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">testSubmit_dateTime</span><span class="p">()</span>
<span class="p">{</span>
<span class="nv">$form</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="na">factory</span><span class="o">-></span><span class="na">create</span><span class="p">(</span><span class="s1">'datetime'</span><span class="p">,</span> <span class="k">null</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span>
<span class="s1">'data_timezone'</span> <span class="o">=></span> <span class="s1">'UTC'</span><span class="p">,</span>
<span class="s1">'user_timezone'</span> <span class="o">=></span> <span class="s1">'UTC'</span><span class="p">,</span>
<span class="s1">'date_widget'</span> <span class="o">=></span> <span class="s1">'choice'</span><span class="p">,</span>
<span class="s1">'time_widget'</span> <span class="o">=></span> <span class="s1">'choice'</span><span class="p">,</span>
<span class="s1">'input'</span> <span class="o">=></span> <span class="s1">'datetime'</span><span class="p">,</span>
<span class="p">));</span>
<span class="nv">$form</span><span class="o">-></span><span class="na">bind</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
<span class="s1">'date'</span> <span class="o">=></span> <span class="k">array</span><span class="p">(</span>
<span class="s1">'day'</span> <span class="o">=></span> <span class="s1">'2'</span><span class="p">,</span>
<span class="s1">'month'</span> <span class="o">=></span> <span class="s1">'6'</span><span class="p">,</span>
<span class="s1">'year'</span> <span class="o">=></span> <span class="s1">'2010'</span><span class="p">,</span>
<span class="p">),</span>
<span class="s1">'time'</span> <span class="o">=></span> <span class="k">array</span><span class="p">(</span>
<span class="s1">'hour'</span> <span class="o">=></span> <span class="s1">'3'</span><span class="p">,</span>
<span class="s1">'minute'</span> <span class="o">=></span> <span class="s1">'4'</span><span class="p">,</span>
<span class="p">),</span>
<span class="p">));</span>
<span class="nv">$dateTime</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\DateTime</span><span class="p">(</span><span class="s1">'2010-06-02 03:04:00 UTC'</span><span class="p">);</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">assertDateTimeEquals</span><span class="p">(</span><span class="nv">$dateTime</span><span class="p">,</span> <span class="nv">$form</span><span class="o">-></span><span class="na">getData</span><span class="p">());</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">testSubmit_string</span><span class="p">()</span>
<span class="p">{</span>
<span class="nv">$form</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="na">factory</span><span class="o">-></span><span class="na">create</span><span class="p">(</span><span class="s1">'datetime'</span><span class="p">,</span> <span class="k">null</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span>
<span class="s1">'data_timezone'</span> <span class="o">=></span> <span class="s1">'UTC'</span><span class="p">,</span>
<span class="s1">'user_timezone'</span> <span class="o">=></span> <span class="s1">'UTC'</span><span class="p">,</span>
<span class="s1">'input'</span> <span class="o">=></span> <span class="s1">'string'</span><span class="p">,</span>
<span class="s1">'date_widget'</span> <span class="o">=></span> <span class="s1">'choice'</span><span class="p">,</span>
<span class="s1">'time_widget'</span> <span class="o">=></span> <span class="s1">'choice'</span><span class="p">,</span>
<span class="p">));</span>
<span class="nv">$form</span><span class="o">-></span><span class="na">bind</span><span class="p">(</span><span class="k">array</span><span class="p">(</span>
<span class="s1">'date'</span> <span class="o">=></span> <span class="k">array</span><span class="p">(</span>
<span class="s1">'day'</span> <span class="o">=></span> <span class="s1">'2'</span><span class="p">,</span>
<span class="s1">'month'</span> <span class="o">=></span> <span class="s1">'6'</span><span class="p">,</span>
<span class="s1">'year'</span> <span class="o">=></span> <span class="s1">'2010'</span><span class="p">,</span>
<span class="p">),</span>
<span class="s1">'time'</span> <span class="o">=></span> <span class="k">array</span><span class="p">(</span>
<span class="s1">'hour'</span> <span class="o">=></span> <span class="s1">'3'</span><span class="p">,</span>
<span class="s1">'minute'</span> <span class="o">=></span> <span class="s1">'4'</span><span class="p">,</span>
<span class="p">),</span>
<span class="p">));</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">assertEquals</span><span class="p">(</span><span class="s1">'2010-06-02 03:04:00'</span><span class="p">,</span> <span class="nv">$form</span><span class="o">-></span><span class="na">getData</span><span class="p">());</span>
<span class="p">}</span>
<span class="o">...</span>
<span class="p">}</span>
</pre></div></td></tr></tbody></table></div>
</div>
<!-- more-->
<p>Okay, let me be frank; I really can’t stand PHP.</p>
<p>Actually, neither can other people; Googling for “worst programming language ever” yields a (closed) stackoverflow poll where PHP is the runaway “winner”, with more than twice as many votes as the runner-up.</p>
<p>I’m not sure that post really captures what’s wrong with the language, though. My impression, as I write code, is that it’s the worst at what it needs to be good at, which is helping people to write correct back-end web code.</p>
<p>To pick on the single most obvious thing, the way that PHP programs assemble HTML from scraps of strings is totally appalling. This language has learned exactly nothing from the work of John McCarthy. Which is now fifty years old.</p>
<p>RIP.</p>
<p>I’m also intrigued by the fact that git gists provide no syntax coloring for PHP, and I wonder whether maybe there’s an interesting reason for that.</p>
<p>What do I notice about this code? Well, for one thing, there are two function definitions in it, and they overlap <em>hugely</em>. This suggests to me that either PHP has terrible abstraction facilities, or that this code was written by someone who just didn’t care. Or, possibly, that it was generated automatically; I don’t recall seeing a note to that effect.</p>Random Code 7: shurn:http-www-brinckerhoff-org:-blog-2012-04-11-random-code-7-sh2012-04-11T15:09:00Z2012-04-11T15:09:00ZJohn Clements
<div class="brush: sh">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="c1"># Check for updates on initial load...</span>
<span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$DISABLE_AUTO_UPDATE</span><span class="s2">"</span> !<span class="o">=</span> <span class="s2">"true"</span> <span class="o">]</span>
<span class="k">then</span>
/usr/bin/env <span class="nv">ZSH</span><span class="o">=</span><span class="nv">$ZSH</span> zsh <span class="nv">$ZSH</span>/tools/check_for_upgrade.sh
<span class="k">fi</span>
<span class="c1"># Initializes Oh My Zsh</span>
<span class="c1"># add a function path</span>
<span class="nv">fpath</span><span class="o">=(</span><span class="nv">$ZSH</span>/functions <span class="nv">$ZSH</span>/completions <span class="nv">$fpath</span><span class="o">)</span>
<span class="c1"># Load all of the config files in ~/oh-my-zsh that end in .zsh</span>
<span class="c1"># TIP: Add files you don't want in git to .gitignore</span>
<span class="k">for</span> config_file <span class="o">(</span><span class="nv">$ZSH</span>/lib/*.zsh<span class="o">)</span> <span class="nb">source</span> <span class="nv">$config_file</span>
<span class="c1"># Set ZSH_CUSTOM to the path where your custom config files</span>
<span class="c1"># and plugins exists, or else we will use the default custom/</span>
<span class="k">if</span> <span class="o">[[</span> -z <span class="s2">"</span><span class="nv">$ZSH_CUSTOM</span><span class="s2">"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
<span class="nv">ZSH_CUSTOM</span><span class="o">=</span><span class="s2">"</span><span class="nv">$ZSH</span><span class="s2">/custom"</span>
<span class="k">fi</span>
is_plugin<span class="o">()</span> <span class="o">{</span>
<span class="nb">local</span> <span class="nv">base_dir</span><span class="o">=</span><span class="nv">$1</span>
<span class="nb">local</span> <span class="nv">name</span><span class="o">=</span><span class="nv">$2</span>
<span class="nb">test</span> -f <span class="nv">$base_dir</span>/plugins/<span class="nv">$name</span>/<span class="nv">$name</span>.plugin.zsh <span class="se">\</span>
<span class="o">||</span> <span class="nb">test</span> -f <span class="nv">$base_dir</span>/plugins/<span class="nv">$name</span>/_<span class="nv">$name</span>
<span class="o">}</span>
<span class="c1"># Add all defined plugins to fpath. This must be done</span>
<span class="c1"># before running compinit.</span>
<span class="k">for</span> plugin <span class="o">(</span><span class="nv">$plugins</span><span class="o">)</span><span class="p">;</span> <span class="k">do</span>
<span class="k">if</span> is_plugin <span class="nv">$ZSH_CUSTOM</span> <span class="nv">$plugin</span><span class="p">;</span> <span class="k">then</span>
<span class="nv">fpath</span><span class="o">=(</span><span class="nv">$ZSH_CUSTOM</span>/plugins/<span class="nv">$plugin</span> <span class="nv">$fpath</span><span class="o">)</span>
<span class="k">elif</span> is_plugin <span class="nv">$ZSH</span> <span class="nv">$plugin</span><span class="p">;</span> <span class="k">then</span>
<span class="nv">fpath</span><span class="o">=(</span><span class="nv">$ZSH</span>/plugins/<span class="nv">$plugin</span> <span class="nv">$fpath</span><span class="o">)</span>
<span class="k">fi</span>
<span class="k">done</span>
<span class="c1"># Load and run compinit</span>
autoload -U compinit
compinit -i
<span class="c1"># Load all of the plugins that were defined in ~/.zshrc</span>
<span class="k">for</span> plugin <span class="o">(</span><span class="nv">$plugins</span><span class="o">)</span><span class="p">;</span> <span class="k">do</span>
<span class="k">if</span> <span class="o">[</span> -f <span class="nv">$ZSH_CUSTOM</span>/plugins/<span class="nv">$plugin</span>/<span class="nv">$plugin</span>.plugin.zsh <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
<span class="nb">source</span> <span class="nv">$ZSH_CUSTOM</span>/plugins/<span class="nv">$plugin</span>/<span class="nv">$plugin</span>.plugin.zsh
<span class="k">elif</span> <span class="o">[</span> -f <span class="nv">$ZSH</span>/plugins/<span class="nv">$plugin</span>/<span class="nv">$plugin</span>.plugin.zsh <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
<span class="nb">source</span> <span class="nv">$ZSH</span>/plugins/<span class="nv">$plugin</span>/<span class="nv">$plugin</span>.plugin.zsh
<span class="k">fi</span>
<span class="k">done</span>
<span class="c1"># Load all of your custom configurations from custom/</span>
<span class="k">for</span> config_file <span class="o">(</span><span class="nv">$ZSH_CUSTOM</span>/*.zsh<span class="o">)</span> <span class="nb">source</span> <span class="nv">$config_file</span>
<span class="c1"># Load the theme</span>
<span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$ZSH_THEME</span><span class="s2">"</span> <span class="o">=</span> <span class="s2">"random"</span> <span class="o">]</span>
<span class="k">then</span>
<span class="nv">themes</span><span class="o">=(</span><span class="nv">$ZSH</span>/themes/*zsh-theme<span class="o">)</span>
<span class="nv">N</span><span class="o">=</span><span class="si">${#</span><span class="nv">themes</span><span class="p">[@]</span><span class="si">}</span>
<span class="o">((</span><span class="nv">N</span><span class="o">=(</span>RANDOM%N<span class="o">)</span>+1<span class="o">))</span>
<span class="nv">RANDOM_THEME</span><span class="o">=</span><span class="si">${</span><span class="nv">themes</span><span class="p">[</span><span class="nv">$N</span><span class="p">]</span><span class="si">}</span>
<span class="nb">source</span> <span class="s2">"</span><span class="nv">$RANDOM_THEME</span><span class="s2">"</span>
<span class="nb">echo</span> <span class="s2">"[oh-my-zsh] Random theme '</span><span class="nv">$RANDOM_THEME</span><span class="s2">' loaded..."</span>
<span class="k">else</span>
<span class="k">if</span> <span class="o">[</span> ! <span class="s2">"</span><span class="nv">$ZSH_THEME</span><span class="s2">"</span> <span class="o">=</span> <span class="s2">""</span> <span class="o">]</span>
<span class="k">then</span>
<span class="k">if</span> <span class="o">[</span> -f <span class="s2">"</span><span class="nv">$ZSH</span><span class="s2">/custom/</span><span class="nv">$ZSH_THEME</span><span class="s2">.zsh-theme"</span> <span class="o">]</span>
<span class="k">then</span>
<span class="nb">source</span> <span class="s2">"</span><span class="nv">$ZSH</span><span class="s2">/custom/</span><span class="nv">$ZSH_THEME</span><span class="s2">.zsh-theme"</span>
<span class="k">else</span>
<span class="nb">source</span> <span class="s2">"</span><span class="nv">$ZSH</span><span class="s2">/themes/</span><span class="nv">$ZSH_THEME</span><span class="s2">.zsh-theme"</span>
<span class="k">fi</span>
<span class="k">fi</span>
<span class="k">fi</span>
</pre></div></td></tr></tbody></table></div>
</div>
<!-- more-->
<p>Shell scripting! “Shell” is the fourth most popular language on github, and this is the most-forked project, “oh my zsh”.</p>
<p>Interestingly, shell scripts actually have a number of features in common with some recent programming languages. In particular, they typically feature lazy evaluation, and they have nice foreach loops.</p>
<p>They don’t really have values, per se, which is interesting; the commands have output that can be piped into other commands, but the values of the language are basically just strings. Well, okay, I suppose strings are values. How do you capture the output of a program as a string? I should know that.</p>
<p>They’re also heavily tied to the notion that each line is its own statement, following the lead of Ruby (and Python?).</p>
<p>There are even function definitions!</p>random code 6: Pythonurn:http-www-brinckerhoff-org:-blog-2012-04-09-random-code-6-python2012-04-09T14:23:00Z2012-04-09T14:23:00ZJohn Clements
<div class="brush: python">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span></pre></div></td>
<td class="code">
<div>
<pre><span></span><span class="k">class</span> <span class="nc">SelectDateWidget</span><span class="p">(</span><span class="n">Widget</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> A Widget that splits date input into three <select> boxes.</span>
<span class="sd"> This also serves as an example of a Widget that has more than one HTML</span>
<span class="sd"> element and hence implements value_from_datadict.</span>
<span class="sd"> """</span>
<span class="n">none_value</span> <span class="o">=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="s1">'---'</span><span class="p">)</span>
<span class="n">month_field</span> <span class="o">=</span> <span class="s1">'</span><span class="si">%s</span><span class="s1">_month'</span>
<span class="n">day_field</span> <span class="o">=</span> <span class="s1">'</span><span class="si">%s</span><span class="s1">_day'</span>
<span class="n">year_field</span> <span class="o">=</span> <span class="s1">'</span><span class="si">%s</span><span class="s1">_year'</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attrs</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">years</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="c1"># years is an optional list/tuple of years to use in the "year" select box.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">attrs</span> <span class="o">=</span> <span class="n">attrs</span> <span class="ow">or</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">required</span> <span class="o">=</span> <span class="n">required</span>
<span class="k">if</span> <span class="n">years</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">years</span> <span class="o">=</span> <span class="n">years</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">this_year</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">today</span><span class="p">()</span><span class="o">.</span><span class="n">year</span>
<span class="bp">self</span><span class="o">.</span><span class="n">years</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="n">this_year</span><span class="p">,</span> <span class="n">this_year</span><span class="o">+</span><span class="mi">10</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">render</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">attrs</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">year_val</span><span class="p">,</span> <span class="n">month_val</span><span class="p">,</span> <span class="n">day_val</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">year</span><span class="p">,</span> <span class="n">value</span><span class="o">.</span><span class="n">month</span><span class="p">,</span> <span class="n">value</span><span class="o">.</span><span class="n">day</span>
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
<span class="n">year_val</span> <span class="o">=</span> <span class="n">month_val</span> <span class="o">=</span> <span class="n">day_val</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">basestring</span><span class="p">):</span>
<span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">USE_L10N</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">input_format</span> <span class="o">=</span> <span class="n">get_format</span><span class="p">(</span><span class="s1">'DATE_INPUT_FORMATS'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">v</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">input_format</span><span class="p">)</span>
<span class="n">year_val</span><span class="p">,</span> <span class="n">month_val</span><span class="p">,</span> <span class="n">day_val</span> <span class="o">=</span> <span class="n">v</span><span class="o">.</span><span class="n">year</span><span class="p">,</span> <span class="n">v</span><span class="o">.</span><span class="n">month</span><span class="p">,</span> <span class="n">v</span><span class="o">.</span><span class="n">day</span>
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">match</span> <span class="o">=</span> <span class="n">RE_DATE</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">if</span> <span class="n">match</span><span class="p">:</span>
<span class="n">year_val</span><span class="p">,</span> <span class="n">month_val</span><span class="p">,</span> <span class="n">day_val</span> <span class="o">=</span> <span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">match</span><span class="o">.</span><span class="n">groups</span><span class="p">()]</span>
<span class="n">choices</span> <span class="o">=</span> <span class="p">[(</span><span class="n">i</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">years</span><span class="p">]</span>
<span class="n">year_html</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_select</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">year_field</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">year_val</span><span class="p">,</span> <span class="n">choices</span><span class="p">)</span>
<span class="n">choices</span> <span class="o">=</span> <span class="n">MONTHS</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
<span class="n">month_html</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_select</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">month_field</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">month_val</span><span class="p">,</span> <span class="n">choices</span><span class="p">)</span>
<span class="n">choices</span> <span class="o">=</span> <span class="p">[(</span><span class="n">i</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">32</span><span class="p">)]</span>
<span class="n">day_html</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_select</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">day_field</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">day_val</span><span class="p">,</span> <span class="n">choices</span><span class="p">)</span>
<span class="n">output</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">field</span> <span class="ow">in</span> <span class="n">_parse_date_fmt</span><span class="p">():</span>
<span class="k">if</span> <span class="n">field</span> <span class="o">==</span> <span class="s1">'year'</span><span class="p">:</span>
<span class="n">output</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">year_html</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">field</span> <span class="o">==</span> <span class="s1">'month'</span><span class="p">:</span>
<span class="n">output</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">month_html</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">field</span> <span class="o">==</span> <span class="s1">'day'</span><span class="p">:</span>
<span class="n">output</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">day_html</span><span class="p">)</span>
<span class="k">return</span> <span class="n">mark_safe</span><span class="p">(</span><span class="sa">u</span><span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">output</span><span class="p">))</span>
</pre></div></td></tr></tbody></table></div>
</div>
<!-- more-->
<p>Python, the new language that’s taking over the world.</p>
<p>This is the third most common language on GitHub, and this file is taken from django, everyone’s favorite web framework except perhaps for Ruby on Rails.</p>
<p>So, what are we seeing here? Well, Python is well-known for being a whitespace-matters language, part of the great backlash against “classic” parsing technology, and so there are no curlies required for method bodies, or semicolons for statement endings. At this point, I think we’re far enough along to take this in stride.</p>
<p>We’ve clearly also got superclasses, dynamic typing, default arguments, some pattern-matching, ooh! nice list comprehensions.</p>
<p>Naturally enough, you’ve also got lots of nasty things like an array append operator that performs needless mutation, and good old return. Honestly, in a language where mutation is the norm, return definitely improves readability.</p>
<p>Basically, looks like a pretty straightforward language; fairly readable, nothing much to complain about. Maybe it’s time to go to stranger things!</p>Random Code 5: opoourn:http-www-brinckerhoff-org:-blog-2012-04-05-random-code-5-opoo2012-04-06T02:45:00Z2012-04-06T02:45:00ZJohn Clements
<div class="brush: ruby">
<div class="source">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span></pre></div></td>
<td class="code">
<div>
<pre><span></span> <span class="k">def</span> <span class="nf">link</span>
<span class="k">if</span> <span class="n">f</span><span class="o">.</span><span class="n">linked_keg</span><span class="o">.</span><span class="n">directory?</span> <span class="ow">and</span> <span class="n">f</span><span class="o">.</span><span class="n">linked_keg</span><span class="o">.</span><span class="n">realpath</span> <span class="o">==</span> <span class="n">f</span><span class="o">.</span><span class="n">prefix</span>
<span class="n">opoo</span> <span class="s2">"This keg was marked linked already, continuing anyway"</span>
<span class="c1"># otherwise Keg.link will bail</span>
<span class="n">f</span><span class="o">.</span><span class="n">linked_keg</span><span class="o">.</span><span class="n">unlink</span>
<span class="k">end</span>
<span class="n">keg</span> <span class="o">=</span> <span class="no">Keg</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">prefix</span><span class="p">)</span>
<span class="n">keg</span><span class="o">.</span><span class="n">link</span>
<span class="k">rescue</span> <span class="no">Exception</span> <span class="o">=></span> <span class="n">e</span>
<span class="n">onoe</span> <span class="s2">"The linking step did not complete successfully"</span>
<span class="nb">puts</span> <span class="s2">"The formula built, but is not symlinked into </span><span class="si">#{</span><span class="no">HOMEBREW_PREFIX</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">puts</span> <span class="s2">"You can try again using `brew link </span><span class="si">#{</span><span class="n">f</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">'"</span>
<span class="n">keg</span><span class="o">.</span><span class="n">unlink</span>
<span class="n">ohai</span> <span class="n">e</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">backtrace</span> <span class="k">if</span> <span class="no">ARGV</span><span class="o">.</span><span class="n">debug?</span>
<span class="vi">@show_summary_heading</span> <span class="o">=</span> <span class="kp">true</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">fix_install_names</span>
<span class="no">Keg</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">prefix</span><span class="p">)</span><span class="o">.</span><span class="n">fix_install_names</span>
<span class="k">rescue</span> <span class="no">Exception</span> <span class="o">=></span> <span class="n">e</span>
<span class="n">onoe</span> <span class="s2">"Failed to fix install names"</span>
<span class="nb">puts</span> <span class="s2">"The formula built, but you may encounter issues using it or linking other"</span>
<span class="nb">puts</span> <span class="s2">"formula against it."</span>
<span class="n">ohai</span> <span class="n">e</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">backtrace</span> <span class="k">if</span> <span class="no">ARGV</span><span class="o">.</span><span class="n">debug?</span>
<span class="vi">@show_summary_heading</span> <span class="o">=</span> <span class="kp">true</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">clean</span>
<span class="nb">require</span> <span class="s1">'cleaner'</span>
<span class="no">Cleaner</span><span class="o">.</span><span class="n">new</span> <span class="n">f</span>
<span class="k">rescue</span> <span class="no">Exception</span> <span class="o">=></span> <span class="n">e</span>
<span class="n">opoo</span> <span class="s2">"The cleaning step did not complete successfully"</span>
<span class="nb">puts</span> <span class="s2">"Still, the installation was successful, so we will link it into your prefix"</span>
<span class="n">ohai</span> <span class="n">e</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">backtrace</span> <span class="k">if</span> <span class="no">ARGV</span><span class="o">.</span><span class="n">debug?</span>
<span class="vi">@show_summary_heading</span> <span class="o">=</span> <span class="kp">true</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">pour</span>
<span class="n">fetched</span><span class="p">,</span> <span class="n">downloader</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">fetch</span>
<span class="n">f</span><span class="o">.</span><span class="n">verify_download_integrity</span> <span class="n">fetched</span><span class="p">,</span> <span class="n">f</span><span class="o">.</span><span class="n">bottle_sha1</span><span class="p">,</span> <span class="s2">"SHA1"</span>
<span class="no">HOMEBREW_CELLAR</span><span class="o">.</span><span class="n">cd</span> <span class="k">do</span>
<span class="n">downloader</span><span class="o">.</span><span class="n">stage</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div></td></tr></tbody></table></div>
</div>
<!-- more-->
<p>Apparently, this is Ruby. This is taken from the most-forked Ruby project on GitHub, “homebrew”—a package manager for OS X. As usual, this piece of code is selected randomly from the project’s source code.</p>
<p>I honestly haven’t looked at a lot of Ruby, but there are a number of interesting things about it.</p>
<p>First of all, I’m guessing “opoo” and “onoe” aren’t built-in forms. Despite the silliness, though, the names were clearly both chosen to be four characters long, so that the code lines up nicely.</p>
<p>Also, it appears that Ruby has a fairly declarative style; I’m not seeing a sequence of actions … well, maybe I am. Perhaps I’m basing that on other pieces of Ruby I’ve read.</p>
<p>It looks like the syntactic designers of Ruby were extremely focused on eliminating delimiters; no curly braces, no parens for applications, no semicolons at the end of lines. I also appreciate the nifty unquote form that’s possible with hash-curly in strings. Also, it looks like there’s some nice pattern-matching on local variable definitions.</p>
<p>I definitely like the nice short functions; I have no idea if that’s characteristic of the language as a whole.</p>
<p>I’m also intrigued by the ‘require’ form that occurs inside of the definition of ‘clean’; does Ruby have local imports?</p>
<p>Finally, I would point out that this code doesn’t seem to have any comments, but that on the other hand it really doesn’t need them all that much. I would have appreciated a purpose statement for each function, but I can deal with not having them.</p>