Geoff Greer's site Geoff Greer 2018-08-15T09:54:28-07:00 Conserve Vertical Pixels 2018-04-02T00:07:15-07:00 <blockquote> <p>Every vertical pixel used for the UI bar signifies a theft from those who hunger and are not fed, those who are cold and are not clothed. <br /><br />— <a href="">Fakey Fakerson</a><sup id="fnref:fakey_tweet"><a href="#fn:fakey_tweet" class="footnote">1</a></sup></p> </blockquote> <p>Here’s a screenshot of Red Hat’s <a href="">OpenShift Console</a> viewed with Firefox on stock GNOME Shell:</p> <p><img src="/images/Screenshot from 2018-03-29 17-30-32.png" alt="Openshift console on" /></p> <p>You might notice a problem with this user interface: The top third of the screen is permanently occupied with stuff I don’t care about.<sup id="fnref:ui_issues"><a href="#fn:ui_issues" class="footnote">2</a></sup></p> <p>This screenshot is particularly egregious, but it exemplifies a common issue. Every layer in the UI stack eats vertical pixels. The OS has a menu bar. The application window has a title bar. The browser has tab and location bars. Finally, the website has two fixed bars: one containing a logo and user info; another for project info. Combine all of these with modern 16:9 screens, and you have a recipe for frustration.</p> <p>I’m sure if you asked each UI designer involved, they’d feel justified in their decision. The OS needs a menu bar. Application windows need title bars. Browsers need location and tab bars. No single pebble is responsible for the avalanche.</p> <p>But if you are a web designer, and you think that having a fixed bar on your site makes for happier users, you are almost certainly mistaken. If you <em>must</em> add a top bar, hide it as the user scrolls down, then show it on scroll up. This interaction pattern is common on mobile devices and it’s not much effort to add to PCs. You can use a library like <a href="">Headroom.js</a>.</p> <p>Hopefully, future designers will look back on this era of vertical annexation the same way we view excesses such as the <code>&lt;blink&gt;</code> tag.</p> <hr /> <div class="footnotes"> <ol> <li id="fn:fakey_tweet"> <p>Hat tip to Gwern for bringing this tweet to my attention. <a href="#fnref:fakey_tweet" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:ui_issues"> <p>Vertical space isn’t the only issue with that UI. The fonts are small and low contrast. The scrollbar takes up the entire height of the browser window, but the top two bars are fixed. Also, there’s a ton of wasted space on the right where that log viewer could expand to. <a href="#fnref:ui_issues" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> Linux Laptop Locking 2018-01-02T03:49:05-08:00 <p>If you wrote your own systemd unit to lock your laptop on suspend, you might want to double-check its behavior. The top two Google results for <a href="">“systemd lock laptop on suspend”</a> both provide examples that lock on <em>resume</em>, not suspend.<sup id="fnref:google"><a href="#fn:google" class="footnote">1</a></sup> This is a security risk.</p> <p>How did I discover this? A few months ago, I switched to <a href="">Sway</a>, a <a href="">tiling window manager</a> similar to <a href="">i3</a>.<sup id="fnref:ubuntu"><a href="#fn:ubuntu" class="footnote">2</a></sup> Like i3, Sway requires a significant amount of configuration to get behaviors that Mac users take for granted.</p> <p>One feature I wanted was to lock the screen when I closed my laptop’s lid. Like any lazy programmer I googled some terms, consulted <a href="">the first Stack Exchange link</a>, and created the necessary systemd unit:</p> <figure class="highlight"><pre><code class="language-ini" data-lang="ini"><span></span><span class="k">[Unit]</span> <span class="na">Description</span><span class="o">=</span><span class="s">Lock the screen</span> <span class="k">[Service]</span> <span class="na">User</span><span class="o">=</span><span class="s">ggreer</span> <span class="na">Environment</span><span class="o">=</span><span class="s">DISPLAY=:0</span> <span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/local/bin/lock-screen</span> <span class="k">[Install]</span> <span class="na">WantedBy</span><span class="o">=</span><span class="s"></span></code></pre></figure> <p>This is a pretty straightforward unit. On suspend, run <code>lock-screen</code>. Unfortunately, it’s wrong.</p> <p>A few weeks after adding the unit, I opened my laptop and stared at an unlocked screen. Immediately, I delved into logs to figure out how this happened. It wasn’t long before I found the answer: The system had failed to suspend <a href="">because of an sshfs mount</a>. This was a double surprise. I didn’t know that:</p> <ol> <li>A non-root process could prevent the kernel from suspending.</li> <li>My systemd unit was locking after suspend instead of before.</li> </ol> <p><a href="">The fix</a> didn’t require changing much:</p> <figure class="highlight"><pre><code class="language-diff" data-lang="diff"><span></span> [Unit] Description=Lock the screen <span class="gi"></span> [Service] User=ggreer Environment=DISPLAY=:0 ExecStart=/usr/local/bin/lock-screen [Install] <span class="gd"></span> <span class="gi"></span></code></pre></figure> <p>Adding “<code>Before=...</code>” forces systemd to wait for <code>lock-screen</code> to start before suspending.<sup id="fnref:systemd_unit"><a href="#fn:systemd_unit" class="footnote">3</a></sup> Using <code></code> is a little more robust, as <code></code> only covers suspending to RAM. Sleep covers suspending to RAM, suspending to disk, and <a href="">hybrid sleep</a>.</p> <p>If you’re running a highly-customized Linux GUI, you’ll probably never be as secure as stock Fedora or Ubuntu. A single mistake (such as the one I made) can leave your system totally vulnerable. Less popular window managers often lack basic exploit mitigation techniques such as <a href="">clearing passwords from memory</a>.</p> <hr /> <div class="footnotes"> <ol> <li id="fn:google"> <p>As of 2018-01-01, the top two results are <a href="">an Arch Linux forum post</a> and <a href="">a Stack Exchange answer</a>. Both use <code></code> and omit <code>Before=...</code>. <a href="#fnref:google" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:ubuntu"> <p>The release of Ubuntu 17.10 switched from Unity to Gnome Shell, making the user interface a nightmare. It’s like they tried their hardest to annoy users. For example, joining a wifi network went from two clicks to five. I’d rather deal with stupid config files and alpha-quality tiling window managers than continue to use Gnome Shell. <a href="#fnref:ubuntu" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:systemd_unit"> <p>More information on the behavior of <code>Before=</code> and <code>After=</code> can be found in <a href="">systemd’s unit documentation</a>. <a href="#fnref:systemd_unit" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> Freedom of Speech isn't About Speech 2017-10-05T22:26:24-07:00 <p>There’s been a lot of debate about free speech lately, and I’ve noticed that people on both sides often misunderstand why it’s a good idea. It’s commonly assumed that freedom of speech is about the right of the speaker to express their ideas, but if you read early formulations of the concept, you’ll find a totally different justification: Free speech is good because it benefits the audience, including those who disagree with the speaker. Freedom of speech isn’t about speech. It’s about hearing.</p> <h2 id="some-history">Some History</h2> <p>A concise version of this argument comes from Thomas Paine’s introduction to <a href=""><em>The Age of Reason</em></a>:</p> <blockquote> <p>You will do me the justice to remember, that I have always strenuously supported the Right of every Man to his own opinion, however different that opinion might be to mine. He who denies to another this right, makes a slave of himself to his present opinion, because he precludes himself the right of changing it.<sup id="fnref:reason_intro"><a href="#fn:reason_intro" class="footnote">1</a></sup></p> </blockquote> <p>Paine wrote this in 1794, while imprisoned in Paris. Paine avoided execution<sup id="fnref:paine_execution"><a href="#fn:paine_execution" class="footnote">2</a></sup> and eventually returned to the US.</p> <p>80 years later, John Stuart Mill made the same point in <a href=""><em>On Liberty</em></a>:</p> <blockquote> <p>But the peculiar evil of silencing the expression of an opinion is, that it is robbing the human race; posterity as well as the existing generation; those who dissent from the opinion, still more than those who hold it. If the opinion is right, they are deprived of the opportunity of exchanging error for truth: if wrong, they lose, what is almost as great a benefit, the clearer perception and livelier impression of truth, produced by its collision with error.<sup id="fnref:liberty"><a href="#fn:liberty" class="footnote">3</a></sup></p> </blockquote> <p>This is the most succinct and powerful argument for free speech that I have come across. It demonstrates why free speech must apply even to repulsive and wrong-headed ideas. We allow bad ideas because they help to strengthen good ideas. Hearing arguments for bad ideas allows us to find their flaws and discover better counterarguments. At the very least, debate forces us to re-examine why we believe what we believe. How do you know the planet is 4.5 billion years old and not 6,000? It’s useful to occasionally rebuild beliefs from the ground up. Doing so helps us be wrong less often.</p> <p>Alright. Let’s say you largely agree with Paine and Mill, but feel that certain things simply aren’t up for debate. Maybe some ideas are just too harmful or detestable to be tolerated in society. Even if that’s true, the cure is likely worse than the disease. Banning ideas creates practical problems.</p> <h2 id="who-decides">Who Decides?</h2> <p>The key question of censorship is: Who decides what to censor? Framing freedom of speech in terms of hearing reveals how insidious this question is. If you ask, “Who should decide which ideas one may speak or publish?”, many are willing to let a government body take the reins. If you ask, “Who should decide which ideas you may hear or read?”, people boggle. But as Paine and Mill pointed out, these are the same question. If you don’t trust others to decide what you can read or hear, then you don’t trust them to decide what can be written or uttered.</p> <h2 id="unintended-consequences">Unintended Consequences</h2> <p>Imagine our society passes laws to ban the publishing of abhorrent and bigoted ideas. No longer are people allowed to express racism, sexism, homophobia, or antisemitism. So we ban <em>Mein Kampf</em>. No great loss there. Can you think of some other influential texts that are full of racism, sexism, homophobia, and antisemitism? A couple come to my mind: The Bible and the Qur’an. Honestly, how can you <em>not</em> ban them? These texts contain passages endorsing <em>slavery</em>. For centuries, the ideas in these books have been used to justify pogroms. Even today, they create needless suffering for much of humanity. If you find yourself struggling to find reasons why religious texts should be exempt, then you see the problem. If censorship laws are consistently applied, most religious texts will be banned. If they’re inconsistently applied, the people in charge will censor according to their own beliefs and biases. Would you trust the current administration with that kind of authority? Neither outcome seems desirable to me.</p> <h2 id="conclusion">Conclusion</h2> <p>The arguments above aren’t new<sup id="fnref:credit"><a href="#fn:credit" class="footnote">4</a></sup>, but they seem to have disappeared from discourse. That’s unfortunate, as freedom of speech is crucial to the well-being of our society. <em>That</em> is why it’s important, not because it’s good for the speaker, and certainly not because it’s some noble ideal to be worshipped for its own sake. The original basis for free speech was pragmatic, not dogmatic. If Paine and Mill had thought that censorship would make people better-off, they would have said so.</p> <p>I’m disappointed that so many people misunderstand this. Hopefully that changes.</p> <hr /> <div class="footnotes"> <ol> <li id="fn:reason_intro"> <p>The full text of Paine’s <em>Age of Reason</em> is available <a href="">here</a>. <a href="#fnref:reason_intro" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:paine_execution"> <p>From <a href="">Wikipedia</a>:</p> <blockquote> <p>Paine narrowly escaped execution. A chalk mark was supposed to be left by the gaoler on the door of a cell to denote that the prisoner inside was due to be removed for execution. In Paine’s case, the mark had accidentally been made on the inside of his door rather than the outside; this was due to the fact that the door of Paine’s cell had been left open whilst the gaoler was making his rounds that day, since Paine had been receiving official visitors. But for this quirk of fate, Paine would have been executed the following morning. He kept his head and survived the few vital days needed to be spared by the fall of Robespierre on 9 Thermidor (July 27, 1794).</p> </blockquote> <p><a href="#fnref:paine_execution" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:liberty"> <p>From <a href="">chapter 2 of <em>On Liberty</em></a> <a href="#fnref:liberty" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:credit"> <p>Credit where credit is due: In addition to Mill &amp; Paine, many of the ideas in this post come from <a href="">a speech by Christopher Hitchens</a>. <a href="#fnref:credit" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> Grandfathered In 2017-09-19T02:36:14-07:00 <p>A useful way to recognize <a href="">status quo bias</a> is to ask, “What things wouldn’t be allowed if they were introduced today?” Here are some examples.</p> <h2 id="drugs">Drugs</h2> <p>The obvious ones: alcohol and tobacco. These are highly addictive and clearly harmful. Tobacco is responsible for ≈20% of premature deaths in the US.<sup id="fnref:tobacco"><a href="#fn:tobacco" class="footnote">1</a></sup> Alcohol is responsible for 10% of working-age deaths.<sup id="fnref:alcohol"><a href="#fn:alcohol" class="footnote">2</a></sup> Had these substances been discovered today, is there any doubt that authorities would crack down on them mercilessly? Is there any doubt that they would have the public’s full support? Our society has gone berserk over far less harmful substances. The reason these drugs are legal is <a href="">path dependence</a>.</p> <p>I’m not even sure if caffeine would be legal. <a href="">It’s addictive</a>, and people <a href="">regularly overdose on it</a>. If not for the centuries-old culture of cafés, it could easily have become a party drug.</p> <!-- prescription only: most over-the-counter medications (cough syrup, tylenol) --> <p>(Note: I am not saying it’s a good idea to ban these drugs, just that they would be banned if invented today.)</p> <h2 id="transportation">Transportation</h2> <p>Several forms of transportation would likely be restricted. Motorcycles are right out. They’re dangerous, noisy, and fueled by a carcinogenic, flammable liquid. It’s hard to convey just how hazardous motorcycles are. According to Wikipedia<sup id="fnref:motorcycle"><a href="#fn:motorcycle" class="footnote">3</a></sup>:</p> <blockquote> <p>Per vehicle mile traveled, motorcyclists’ risk of a fatal crash is 35 times greater than a passenger car.</p> </blockquote> <p>In the US, the fatality rate for motorcycles is 23 per 100 million miles traveled. Assuming a typical rider travels 4,000 miles per year and rides for 40 years, that amounts to a 4% chance of death. That’s only the risk of <em>death</em>. The chance of crippling injury or brain damage is likely higher.</p> <p><a href="">General aviation</a> (that is, private planes) would never be allowed today. Consider how society has reacted to drones. Now imagine drones were 50 times heavier and ran on leaded gasoline. Who would ever permit such machines to fly above their homes? Apparently we would, because they’re called Cessnas.</p> <h2 id="food">Food</h2> <p>Meat would certainly be banned, as it runs afoul of every animal cruelty law. Raising animals for slaughter would be as despised (and as illegal) as dog fighting. Even if meat caused no suffering, it would still be banned due to health concerns. Every year in the US, meat-borne diseases sicken millions and kill around 5,000 people.<sup id="fnref:meat"><a href="#fn:meat" class="footnote">4</a></sup> Had the same rate of illness and death come from Soylent, there would be class-action lawsuits and congressional hearings. People would ask, “How could the FDA let this happen?”</p> <p>Some plants might be stricken from the menu. Today’s produce is the result of selective breeding… or worse. Most grapefruits in your supermarket have radioactive ancestors, courtesy of <a href="">atomic gardening</a>. The changes made in GMOs are far more precise and limited in scope, yet most Americans are wary of ingesting such carefully-crafted organisms. We prefer to play it safe and deal with plants like lemons and celery, which can <a href="">cause chemical burns (warning: graphic images)</a>.</p> <p>Speaking of selective breeding: What about pets? Many dogs suffer from the traits bred into them. Examples include <a href="">Pugs</a>, <a href="">Bulldogs</a>, and <a href="">Shih Tzus</a>. Had these breeds been created today through genetic engineering, the public would be outraged.</p> <h2 id="fluoridation">Fluoridation</h2> <p>Could water fluoridation could happen today? I don’t think so. Too many people would express worry and doubt. Some would ask, “What if fluoride has long-term health consequences?” Others would claim that fluoride causes autism. There would be enough controversy and protest that I doubt any municipality would fluoridate their water. At best it would be like vaccination, with most parents giving fluoride supplements to their children.</p> <!-- Paper money. --> <!-- subwoofers? --> <h2 id="conclusion">Conclusion</h2> <p>These are just a few examples. I can go on, though I’ll spare myself the effort of going into detail. A lot of fun things are just plain dangerous: fireworks, mountaineering, football, boxing, surfing, auto racing. These all reliably kill and cripple people while serving no purpose other than entertainment. I doubt half of them would remain legal if introduced today.</p> <p>Again, I am not saying these things should be banned or restricted. I enjoy alcohol, caffeine, and fireworks (occasionally all at once). I wanted to show how society’s standards have changed so I could make another point: Had the past been as risk-averse as the present, would we be better off? I don’t think so. Does that mean we should we be more enthusiastic about allowing new inventions? Probably.</p> <hr /> <div class="footnotes"> <ol> <li id="fn:tobacco"> <p><a href="">CDC: Smoking &amp; Tobacco Use</a> <a href="#fnref:tobacco" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:alcohol"> <p><a href="">CDC: Alcohol Deaths</a> <a href="#fnref:alcohol" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:motorcycle"> <p><a href="">Wikipedia: Motorcycle Safety</a> <a href="#fnref:motorcycle" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:meat"> <p><a href="">CDC: Food-Related Illness and Death in the United States</a> <a href="#fnref:meat" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> Thinkpad X62 2017-07-16T22:26:25-07:00 <p>Back in January, I <a href="/2017/01/23/oldest-viable-laptop/">used an old Thinkpad</a> while my <a href="/2015/04/19/2015-macbook-review/">12” Macbook</a> was being repaired. I found myself really enjoying some aspects of it. This nudged me down a path that ended with me modding a frankenpad built by some enthusiasts in Shenzhen.</p> <p>Using my old X61s left me frustrated with current laptops. Sure, the X61s was old and slow, but that was to be expected. What I didn’t expect was just how much laptops have regressed. Chiclet-style keyboards are abysmal compared to the keyboard on the X61s. I forgot how much I preferred 4:3 screens for work. Title bars and tabs tend to consume vertical space, which 4:3 screens have plenty of. The X61s screen was dim, but I fixed that with an <a href="">LED backlight conversion kit</a>.</p> <p style="text-align: center; font-size: 80%;"> <a href="/photos/x62/DSC_2305.JPG"><img alt="Dear Lenovo: Please bring back the classic keyboard" src="/photos/x62/DSC_2305.JPG" /></a> <br /> Dear Lenovo: Please bring back this classic keyboard </p> <p>Some features were nice to have, but not particularly compelling: I liked the form factor, though it was a bit thick. The removable battery came in handy a few times. And I enjoyed little details like the latching lid and thin bezel.</p> <p>Of course, some aspects of the X61s were embarassing by modern standards. The screen resolution was only 1024×768, and not <a href="">IPS</a>, meaning colors changed with viewing angle. The VGA-out restricted possibilities for external displays. Performance and battery life were… less than ideal. Even a maxxed-out machine (1.8GHz Core 2 Duo, 8GB of RAM, SATAII SSD) was a little sluggish for work.</p> <p>Despite its shortcomings, I ended up using the X61s more than my 12” MacBook. The X61s convinced me that a much better laptop could exist. The same chassis with modern components would be a very compelling product.</p> <h3 id="the-x62">The X62</h3> <p>In the quest for something better, I stumbled upon the X62. This “model” isn’t made by Lenovo. It’s the product of <a href="">51nb</a>, a group of enthusiasts in Shenzhen. The X62 is an X61 chassis but with:</p> <ul> <li>A 12” 1400×1050 IPS LCD (likely salvaged from an X60 tablet).</li> <li>An Intel <a href="">Core i7-5600U</a> (Broadwell. Dual core. Turbo boost up to 3.2GHz.)</li> <li>Up to 32GB of RAM.</li> <li>Mini DisplayPort &amp; mini-HDMI out.</li> <li>802.11ac, Bluetooth 4, USB 3, SD card reader, Gigabit Ethernet.</li> <li>SATA3 &amp; mSATA.</li> </ul> <p>I ordered one back in March and received it in June. As with the X61s, I replaced the backlight with an LED kit. This improved battery life and brought the screen brightness from 160 nits to over 600. The backlight mod took hours, as it involved disassembling most of the laptop.</p> <p><img src="/photos/x62/IMG_1163.jpg" alt="ThinkPad X62 disassembled. I'm so glad I only have to do this once." /></p> <p>You can see more pictures of the process <a href="/photos/x62">here</a>.</p> <h3 id="linux">Linux</h3> <p>Ubuntu 17.04 worked out of the box, but there was one annoyance: battery life. For some reason, the laptop was using 10 watts at idle. Thanks to <a href="">some forum posts</a>, I managed to tweak various kernel module options and got idle down to 4 watts. This drastically improved battery life. I then put together a script to enable power savings on startup. These tweaks should benefit most Linux users on modern Intel hardware:</p> <figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="ch">#!/bin/sh</span> <span class="c1"># Disable the NMI watchdog</span> <span class="nb">echo</span> <span class="s1">&#39;0&#39;</span> &gt; <span class="s1">&#39;/proc/sys/kernel/nmi_watchdog&#39;</span><span class="p">;</span> <span class="c1"># Runtime power management for I2C devices</span> <span class="k">for</span> i in /sys/bus/i2c/devices/*/device/power/control <span class="p">;</span> <span class="k">do</span> <span class="nb">echo</span> auto &gt; <span class="si">${</span><span class="nv">i</span><span class="si">}</span> <span class="k">done</span> <span class="c1"># Runtime power-management for PCI devices</span> <span class="k">for</span> i in /sys/bus/pci/devices/*/power/control <span class="p">;</span> <span class="k">do</span> <span class="nb">echo</span> auto &gt; <span class="si">${</span><span class="nv">i</span><span class="si">}</span> <span class="k">done</span> <span class="c1"># Runtime power-management for USB devices</span> <span class="k">for</span> i in /sys/bus/usb/devices/*/power/control <span class="p">;</span> <span class="k">do</span> <span class="nb">echo</span> auto &gt; <span class="si">${</span><span class="nv">i</span><span class="si">}</span> <span class="k">done</span> <span class="c1"># Low power SATA</span> <span class="k">for</span> i in /sys/class/scsi_host/*/link_power_management_policy <span class="p">;</span> <span class="k">do</span> <span class="nb">echo</span> min_power &gt; <span class="si">${</span><span class="nv">i</span><span class="si">}</span> <span class="k">done</span> <span class="c1"># Disable Wake-on-LAN on ethernet port</span> ethtool -s wlan0 wol d<span class="p">;</span> ethtool -s eth0 wol d <span class="c1">#Enable Audio codec power management</span> <span class="nb">echo</span> <span class="s1">&#39;1&#39;</span> &gt; <span class="s1">&#39;/sys/module/snd_hda_intel/parameters/power_save&#39;</span><span class="p">;</span> <span class="c1"># Low power wireless</span> iw dev wlan0 <span class="nb">set</span> power_save on</code></pre></figure> <p>I also had to use Realtek’s driver for the ethernet controller, as the default one wasted power. A <code>sudo apt install r8168-dkms</code> and a module blacklist later, I was in business. With these tweaks, my X62 idles in power state PC6. It’s possible to go lower, but I’m content with the current battery life.</p> <p>I wish Linux had better defaults, but this sort of thing is to be expected when it comes to open source software.</p> <h2 id="conclusion">Conclusion</h2> <p><a href="/photos/x62/DSC_2304.JPG"><img src="/photos/x62/DSC_2304.JPG" alt="ThinkPad X62" /></a></p> <p>The X62 is a niche product, but it really scratches an itch for me. There’s no other way to get a 4:3 matte screen, a great keyboard, and modern performance. My MacBook has become my secondary laptop. I’ve only taken it out of the house once since I got the X62, and that was for my Oregon bikepacking trip.</p> GNOME Terminal Antialiasing Saga 2017-06-14T19:49:46-07:00 <p><a href="/2016/08/26/gnome-terminal-cursor-blinking-saga/">Previously</a>.</p> <p>On lower-DPI displays, <a href="/2013/12/24/programming-fonts/">I like to use bitmap fonts</a> in my terminals and text editors. I was surprised to see that Gnome Terminal still <a href="">antialiased</a> and <a href="">hinted</a> my bitmap font:</p> <div style="text-align: center;"> <img alt="Gnome terminal making stuff blurry" src="/images/Screenshot from 2017-06-11 20-04-00.png" style="width: 471px; height: 239px;" /> </div> <p>Here’s a close-up:</p> <div style="text-align: center;"> <img alt="Enlargement of antialiasing" src="/images/Screenshot from 2017-06-11 20-04-00-crop.png" style="width: 450px; height: 135px; image-rendering: pixelated;" /> </div> <p>The red text is obvious, but you can also see tinges of blue and red on the white text. Not pretty.</p> <p>Other platforms make it easy to get the desired behavior. Both and PuTTY have checkboxes to disable antialiasing and subpixel hinting. But (as anyone familiar with Gnome would expect) Gnome Terminal has no GUI setting to change this.</p> <p>To solve the problem, I delved into <a href="">fontconfig</a>. My goal was to disable antialiasing for just one font. I created <code>~/.fonts.conf</code> and filled it with some guesses based on docs and related Stack Overflow answers:</p> <figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span></span><span class="cp">&lt;?xml version=&#39;1.0&#39;?&gt;</span> <span class="cp">&lt;!DOCTYPE fontconfig SYSTEM &#39;fonts.dtd&#39;&gt;</span> <span class="nt">&lt;fontconfig&gt;</span> <span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&quot;pattern&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&quot;family&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;string&gt;</span>ProggyTinyTTSZ<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;/test&gt;</span> <span class="nt">&lt;edit</span> <span class="na">mode=</span><span class="s">&quot;assign&quot;</span> <span class="na">name=</span><span class="s">&quot;antialias&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;bool&gt;</span>false<span class="nt">&lt;/bool&gt;</span> <span class="nt">&lt;/edit&gt;</span> <span class="nt">&lt;edit</span> <span class="na">mode=</span><span class="s">&quot;assign&quot;</span> <span class="na">name=</span><span class="s">&quot;hinting&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;bool&gt;</span>false<span class="nt">&lt;/bool&gt;</span> <span class="nt">&lt;/edit&gt;</span> <span class="nt">&lt;/match&gt;</span> <span class="nt">&lt;/fontconfig&gt;</span></code></pre></figure> <p>This had no effect. I re-read some fontconfig docs and noticed that <code>~/.fonts.conf</code> had been deprecated for a new config path: <code>~/.config/fontconfig/fonts.conf</code>. I moved the config file. Still no change.</p> <p>After reading <em>more</em> fontconfig docs, I found out about <code>FC_DEBUG</code>:</p> <blockquote> <p>To help diagnose font and applications problems, fontconfig is built with a large amount of internal debugging left enabled. It is controlled by means of the FC_DEBUG environment variable.</p> </blockquote> <p>Surely, debug logging would give me some clues. Naturally, this variable wasn’t just a boolean:</p> <blockquote> <p>The value of this variable is interpreted as a number, and each bit within that value controls different debugging messages.</p> </blockquote> <p>I tried setting <code>FC_DEBUG</code> to 35 (0b0100011), corresponding to verbose info for caching &amp; matching. It turns out that verbose logging lives up to its name:</p> <pre><code>ggreer@zinc:~% FC_DEBUG=35 fc-match -v ProggyTinyTTSZ family antialias hinting file | wc -l 29771 </code></pre> <p>That’s right: almost 30,000 lines of debug logs— almost as useless as no logs. I played with other values, eventually settling on <code>FC_DEBUG=4</code>. That generated “only” 5,000 lines and seemed to contain some useful clues.</p> <p>The first thing I noticed when scouring the debug logs was that many settings were being processed after my user config. I traced this down to the order of config files in <code>/etc/fonts/conf.d/</code>. The rule to load user configs was in the middle, not at the last thing done. To ensure no global config was overriding my directives, I ran <code>sudo mv 50-user.conf 99-user.conf</code>. Debug logs then confirmed that my rules were run last.</p> <p>Still, I saw blurry text.</p> <p>At this point, I’d been at it for almost two hours. I was getting pretty frustrated. With nothing better coming to mind, I stared at my XML. I tediously compared it against examples in the fontconfig docs. I saw one suspicious line: I was using <code>&lt;match target="pattern"&gt;</code>, while many examples used <code>&lt;match target="font"&gt;</code>. I changed the target attribute from “pattern” to “font”:</p> <figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span></span><span class="cp">&lt;?xml version=&#39;1.0&#39;?&gt;</span> <span class="cp">&lt;!DOCTYPE fontconfig SYSTEM &#39;fonts.dtd&#39;&gt;</span> <span class="nt">&lt;fontconfig&gt;</span> <span class="nt">&lt;match</span> <span class="na">target=</span><span class="s">&quot;font&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;test</span> <span class="na">name=</span><span class="s">&quot;family&quot;</span> <span class="na">qual=</span><span class="s">&quot;any&quot;</span> <span class="na">compare=</span><span class="s">&quot;eq&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;string&gt;</span>ProggyTinyTTSZ<span class="nt">&lt;/string&gt;</span> <span class="nt">&lt;/test&gt;</span> <span class="nt">&lt;edit</span> <span class="na">mode=</span><span class="s">&quot;assign&quot;</span> <span class="na">name=</span><span class="s">&quot;antialias&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;bool&gt;</span>false<span class="nt">&lt;/bool&gt;</span> <span class="nt">&lt;/edit&gt;</span> <span class="nt">&lt;edit</span> <span class="na">mode=</span><span class="s">&quot;assign&quot;</span> <span class="na">name=</span><span class="s">&quot;hinting&quot;</span><span class="nt">&gt;</span> <span class="nt">&lt;bool&gt;</span>false<span class="nt">&lt;/bool&gt;</span> <span class="nt">&lt;/edit&gt;</span> <span class="nt">&lt;/match&gt;</span> <span class="nt">&lt;/fontconfig&gt;</span></code></pre></figure> <p>…and was at last rewarded with pixel-perfect text:</p> <div style="text-align: center;"> <img alt="Gnome terminal with correctly rendered fonts" src="/images/Screenshot from 2017-06-11 20-02-44.png" style="width: 471px; height: 239px;" /> </div> <p>A close-up:</p> <div style="text-align: center;"> <img alt="Enlargement of no antialiasing" src="/images/Screenshot from 2017-06-11 20-02-44-crop.png" style="width: 450px; height: 135px; image-rendering: pixelated;" /> </div> <p>Finally!</p> <p>This is yet more evidence of how ridiculously hostile Gnome is to users. I’m no novice, but it took me two hours to accomplish what takes two seconds on every other platform. What a waste.</p> Software Rot 2017-02-28T17:59:53-08:00 <p>In his book <a href="/2016/07/23/age-of-em/"><em>Age of Em: Work, Love and Life when Robots Rule the Earth</em></a>, Robin Hanson briefly discusses software rot:</p> <blockquote> <p>As software that was designed to match one set of tasks, tools, and situations is slowly changed to deal with a steady stream of new tasks, tools, and situations, such software becomes more complex, fragile, and more difficult to usefully change (Lehman and Belady 1985)<sup id="fnref:Lehman"><a href="#fn:Lehman" class="footnote">1</a></sup>. Eventually it is better to start over and write whole new subsystems, and sometimes whole new systems, from scratch.</p> </blockquote> <p>I’m pretty sure this is true. Adapting mature software to new circumstances tends to take more time and effort than writing new software from scratch. Software people don’t like to admit this, but the evidence is clear. Open source software has several high-profile examples.</p> <h2 id="multi-process-firefox">Multi-process Firefox</h2> <p>When it was first written, <a href="">Mozilla Firefox</a> ran everything in a single process. After the release of <a href="">Google Chrome</a>, it was clear that a multi-process model allowed for better security and performance. Mozilla developers soon started planning to make Firefox multi-process. That was in 2007.</p> <p>Almost a decade later, Mozilla finally <a href="">began rollout of multi-process Firefox</a>. This delay is not for want of trying. The teams at Mozilla are talented and driven. Still, Chrome was written from scratch in far less time than it has taken Firefox to change. There are two main reasons for this:</p> <ul> <li>Making a single process architecture multi-process means changing a <em>lot</em> of small things. Certain function calls have to be replaced with inter-process communication. Shared state must be wrapped in mutexes. Caches and local databases must handle concurrent access.</li> <li>Firefox needed to remain compatible with existing add-ons (or force devs to update their add-ons). Chrome got to create an extention API from scratch, avoiding such constraints.</li> </ul> <p>It gets worse. These constraints are at odds with each other: Overhaul the internal architecture, but alter public-facing APIs as little as possible. It’s no wonder Mozilla needed 10 years to accomplish this feat.</p> <h2 id="event-driven-apache">Event-driven Apache</h2> <p>When <a href="">Apache httpd</a> was first written, it used a process-per-connection model. One process would listen on port 80, then <code>accept()</code> and <code>fork()</code>. The child process would then <code>read()</code> and <code>write()</code> on the socket. When the request was finished, the child would <code>close()</code> the socket and <code>exit()</code>.</p> <p>This architecture had the advantage of being simple, easy to implement on many platforms, and… not much else. It was absolutely terrible for performance, especially when handling long-lived connections. To be fair: this <em>was</em> 1995. And Apache soon moved to a threaded model, which did help performance. Still, it couldn’t handle <a href="">10,000 simultaneous connections</a>. A connection-per-thread architecture takes 1,000 threads to service 1,000 concurrent connections. Each thread has its own stack and state, and must be scheduled by the operating system. It makes for a bad time.</p> <p>In contrast, <a href="">Nginx</a> used a <a href="">reactor pattern</a> from the start. This allowed it to handle more concurrent connections and rendered it immune to <a href="">slowloris attacks</a>.</p> <p>Nginx was first released in 2007, and its performance advantage was apparent. Years before the release of Nginx, the Apache devs had begun re-architecting httpd to perform better. The <a href="">event MPM</a> shipped with Apache 2.2 in 2005. Still, there were teething issues. Most importantly, the event MPM broke compatibility with popular modules like mod_php. It wasn’t until 2012 that Apache 2.4 shipped with it as the default.<sup id="fnref:httpd"><a href="#fn:httpd" class="footnote">2</a></sup> While far better than the previous <a href="">prefork</a> and <a href="">worker MPM</a>s, the worker MPM didn’t acheive parity with Nginx. Instead, it used separate thread pools for listening/accepting connections and processing requests. The architecture is roughly equivalent to running a load balancer or reverse proxy in front of a worker MPM httpd.<sup id="fnref:httpd2"><a href="#fn:httpd2" class="footnote">3</a></sup></p> <h2 id="cpython-gil">CPython GIL</h2> <p>Python is a nice programming language. It’s expressive, easy to learn (at least as programming languages go), and it’s supported on a wide variety of platforms. But for the past two decades, the most popular implementation of Python has had one major problem: it can’t easily take advantage of multiple CPU cores.</p> <p>The cause of Python’s lack of parallelism is its global interpreter lock, or GIL. From <a href="">the Python wiki</a>:</p> <blockquote> <p>In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)</p> </blockquote> <p>Originally, the GIL wasn’t a big deal. When Python was created, multi-core systems were rare. And a GIL is simple to write and easy to reason about. But today, even wristwatches have multi-core CPUs. The GIL is an obvious and glaring defect in what is otherwise a pleasant language. Despite CPython’s popularity, despite the project’s capable developers, despite sponsors such as Google, Microsoft, and Intel, <a href="">fixing the GIL isn’t even on the roadmap</a>.</p> <h2 id="conclusion">Conclusion</h2> <p>Even when given talented engineers, plenty of money, and clear vision, mature software can be extremely difficult to change. I tried to find cases that disproved software rot, but they don’t seem to exist. Robin Hanson <a href="">asked for counterexamples</a> and nobody came up with anything convincing. There are plenty of old software projects, but they haven’t had to adapt much. I’d love to find good counterexamples, as the current evidence paints a bleak picture for the long-term future of software.</p> <hr /> <h3 id="read-more">Read more</h3> <ul> <li><a href="">Overcoming Bias: Why Does Software Rot?</a></li> <li><a href="">Suprise: Software rots!</a></li> <li><a href="">Wikipedia: Software rot</a></li> </ul> <hr /> <div class="footnotes"> <ol> <li id="fn:Lehman"> <p>The cite is for a text called <em>Program Evolution: Processes of Software Change</em>. The work is older than me, and I can’t find an online version. I bought a physical copy and have been slowly making my way through it. The terminology is odd, but the conclusions haven’t been particularly surprising. <a href="#fnref:Lehman" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:httpd"> <p>The original version of this blog post contained some misapprehensions about the timeline. Thanks goes to <a href="">Paul Querna</a> for correcting them. <a href="#fnref:httpd" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:httpd2"> <p>Anyone who knows about httpd’s internals will take issue with this sentence. The comparison sacrifices accuracy for brevity. I apologize. <a href="#fnref:httpd2" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> Oldest Viable Laptop 2017-01-23T18:04:30-08:00 <p>What’s the oldest laptop you could reasonably do your job with? 3 years old? 5 years? 10? And if asked the same question 10 years ago, would your number be higher or lower? Thanks to a failing battery in <a href="/2015/04/19/2015-macbook-review/">my 12” MacBook</a>, I discovered my answer.</p> <p>For the 10 days it took to repair my MacBook, I had to use my backup laptop:</p> <p><img src="/photos/pics/thinkpad_x61s.jpg" alt="ThinkPad X61s" /></p> <p>This is a <a href="">ThinkPad X61s</a>. Despite being made in 2007, it’s been fine for work. Yes, everything about it is worse than my MacBook. It’s slower and heavier. It lacks a trackpad. The screen is a mere 1024x768, causing some websites to show their mobile layout.<sup id="fnref:font"><a href="#fn:font" class="footnote">1</a></sup> Still, the experience has been significantly better than I predicted. The only major hardware drawback is the lack of video camera. The main sources of frustration have been software. Ubuntu 16.04 doesn’t have a built-in dictionary or thesaurus. The default calendar app is a joke. <del>And Thunderbird doesn’t have a unified inbox view.</del> (Edit: <a href="">It does</a>. Thanks To Brendan Long for pointing this out.)</p> <p>Had a similar circumstance happened 10 years ago, my oldest viable laptop would not be so old. That is to say: There’s no way that in 2007, I’d be able to get by with a laptop from 1997. The performance issues would be insurmountable.</p> <p>Growing up, I never thought I’d be able to use decade-old hardware without issue. Either laptop improvements are well into diminishing returns, or progress in hardware has stagnated, or both.</p> <p>Update: It’s been two weeks since I got my MacBook back, and I still tend to use my ThinkPad more. I’m not sure if I’ll stick with it, but there’s something about this machine that causes me to favor it.</p> <hr /> <div class="footnotes"> <ol> <li id="fn:font"> <p>My terminal and editor windows had plenty of space thanks to <a href="/2013/12/24/programming-fonts/">pixel-perfect programming fonts</a>. <a href="#fnref:font" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> Ag & Ripgrep: .ignore 2016-09-26T14:12:57-07:00 <p>A few days ago, <a href="">Andrew Gallant</a> (AKA BurntSushi) released <a href="">ripgrep</a>, a search tool similar to to <a href="/ag">ag</a>. To coincide with the initial release, Gallant wrote <a href="">a blog post comparing various search tools</a>. In it, he discusses both the advantages and shortcomings of a half-dozen tools, including ag. He finds bugs, pathological performance cases, and unexpected ways in which these tools can be sped-up. If the topic even remotely interests you, read Gallant’s blog post.</p> <p>When Gallant’s post <a href="">was discussed on Hacker News</a>, I <a href="">replied</a> with my thoughts. This spurred a pleasant and productive discussion. I noticed that both of our tools had ignore files (<code>.agignore</code> and <code>.rgignore</code>), so <a href="">I suggested we converge on a common name and format</a>. We quickly agreed on <code>.ignore</code> (surprisingly, it wasn’t taken). Within a couple of hours, both of us had added the feature into our respective projects.<sup id="fnref:ag"><a href="#fn:ag" class="footnote">1</a></sup><sup id="fnref:rg"><a href="#fn:rg" class="footnote">2</a></sup> The author of <a href="">sift</a> also <a href="">seems to be on board</a>.</p> <p>Support for <code>.ignore</code> files is in ag v0.33.0 and later. If you have <code>.agignore</code> files, don’t worry. You’ll have plenty of time to rename them. It will be at least six months before I deprecate them, and probably a year before they’re no longer read.</p> <p>The whole experience was positive for everyone involved. Andrew and I had an enjoyable exchange. Users of our tools were saved some trouble. And there’s a decent chance that more software will support the same <code>.ignore</code> standard. I’m happy to have played a part in creating this small gem of collaboration.</p> <hr /> <div class="footnotes"> <ol> <li id="fn:ag"> <p><a href="">Ag pull request #974: Prefer .ignore to .agignore</a> <a href="#fnref:ag" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:rg"> <p><a href="">Ripgrep pull request #41: Switch from .rgignore to .ignore</a> <a href="#fnref:rg" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> GNOME Terminal Cursor Blinking Saga 2016-08-26T20:51:37-07:00 <p>When setting up a new computer, one of the first things I do is disable cursor blinking in the terminal. For the past decade, the Gnome team has worked diligently to make this as hard as possible.</p> <div style="text-align: center;"> <img alt="On. Off. On. Off. On. Off..." src="/images/gnome_terminal_cursor_blinking.gif" /> </div> <p>The story begins in 2006. Back then, Gnome Terminal had a checkbox in its settings. Here’s a screenshot from Ubuntu 6.06:</p> <p><img src="/images/gnome_terminal_ubuntu_6.png" alt="GNOME Terminal Settings in Ubuntu 6.06" /></p> <p>Unchecking “Cursor blinks” would stop the cursor from blinking. It was simple and accessible; exactly the kind of UI that has no place in a Gnome project. Some developers soon decided to “simplify” things by going, “…on a quest to remove all annoying tiny little bits in GNOME’s UI.” Instead of having a checkbox, they wanted the terminal to obey the global system setting (for cursors in text editors, browser URL bars, etc). Hence <a href="">Bug 342921 - Cursor blinking preference should follow system defaults</a>. The checkbox was removed in Gnome v2.22, meaning that the only way to disable blinking was to turn it off in the entire Gnome UI. This annoyed many people, as a giant blinking block is far more prominent than a thin blinking line. Users quickly responded. They created issues such as <a href="">Bug 533522 - Alllow override of system blink preference</a> and <a href="">Bug 534207 - Something to fix the cursor blinking problem soon</a>. Gnome was going through a UI freeze at the time, so the “fix” was to create a gconf setting. Now to disable terminal blinking, you had to run:</p> <pre><code>gconftool-2 --set "/apps/gnome-terminal/profiles/Default/cursor_blink" \ --type boolean "False" </code></pre> <p>Good luck figuring that out on your own. Fortunately, the magic invocation was quickly documented on sites such as Stack Overflow. It even made its way to <a href="">a page dedicated to stopping cursor blinks</a>. Things stayed that way for five years.</p> <p>Then Gnome 3 came out.</p> <p>The old magic invocation no longer appeased the Gnome gods. This issue was created: <a href="">Bug 702901 - Disabling blinking cursor not working</a>. The reason for the breakage was twofold. First: Gnome switched from gconf to dconf. Second: Gnome devs changed the config schema for terminal settings. In Gnome 2, each terminal profile was stored by name. This allowed for paths like <code>/profiles/Default/</code> to work across systems. Gnome 3 stored profiles by UUID. Since UUIDs tend to be rather <em>unique</em>, there isn’t a standard default key. One first has to get the UUID of the default profile, then set the appropriate key under it. Like so:</p> <pre><code>% gsettings get org.gnome.Terminal.ProfilesList default 'b1dcc9dd-5262-4d8d-a863-c897e6d979b9' % gsettings set org.gnome.Terminal.Legacy.Profile:/org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9/ cursor-blink-mode off % </code></pre> <p>To make it a one-liner, you have to use a subshell:</p> <pre><code>gsettings set org.gnome.Terminal.Legacy.Profile:/org/gnome/terminal/legacy/profiles:/:$(gsettings get org.gnome.Terminal.ProfilesList default | tr -d \')/ cursor-blink-mode off </code></pre> <p>Annoyingly, this information isn’t in Gnome’s answer to <a href=";redirect=Terminal%2FFAQ#How_can_I_stop_the_cursor_from_blinking.3F">How can I stop the cursor from blinking?</a>. Instead, they link to another answer, which contains this gem:</p> <blockquote> <p>Unfortunately, the gsettings tool can’t currently autocomplete the key names with relocatable schemas (that’s <a href="">this bug</a>), but you can just <a href="">read the schema itself</a>.</p> </blockquote> <p>I cannot recall encountering a more user-hostile experience. How many people are going to read a <em>700 line XML file</em> to tweak their terminal? It’s absurd. There are two possible explanations for such a terrible experience: Either the Gnome developers are indifferent to their users, or they are incompetent. Actually, it could be worse. It could be both.</p> <h3 id="conclusion">Conclusion</h3> <p>The issue to re-add the blink checkbox still exists: <a href="">Bug 559990 - Add UI for the cursor blink preference</a>. I doubt it will be fixed any time soon. In case you were curious: OS X has a non-blinking cursor by default. Changing it requires checking a box in the settings menu:</p> <p><img src="/images/Screen Shot 2016-08-29 at 18.35.49.png" alt="OS X settings" /></p> <p>…just like Gnome had 10 years ago.</p> <p>Desktop Linux is fraught with these sorts of issues. The only reason I use it is because I need to test software on the platform. If not for that, I doubt I’d ever touch a Linux GUI again.</p> <p>Update: <a href="/2017/06/14/gnome-terminal-antialiasing-saga/">the saga continues</a>.</p> Age of Em 2016-07-23T11:21:48-07:00 <p>Back in June, I read <a href="">Robin Hanson</a>’s book: <a href=""><em>Age of Em: Work, Love and Life when Robots Rule the Earth</em></a>. I found it fascinating. Two months later, the book’s ideas still pop into my mind daily. Nothing else I’ve read in the past year has done that. This post is a summary of the core ideas in <em>Age of Em</em>, followed by my observations and critiques.</p> <h2 id="the-author">The Author</h2> <blockquote> <p>I expect my analysis to be relevant for a large cloud of different but similar scenarios. In particular, conditional on my key assumptions, I expect at least 30% of future situations to be usefully informed by my analysis. Unconditionally, I expect at least 10%.<br /> – Robin Hanson, <em>Age of Em</em></p> </blockquote> <p>Let me make my bias known: I am a fan of Robin Hanson. He possesses a rare combination of intelligence, expertise, creativity, and civility. Moreover, he makes exceptional use of these gifts. Hanson looks at the big picture– the <em>really</em> big picture. For example: When examining <a href="">the growth of humanity over millions of years</a>, the invention of writing is a rounding error. At such a high-level view, all of human history can be described by three eras of growth<sup id="fnref:eras"><a href="#fn:eras" class="footnote">1</a></sup>:</p> <ol> <li>2,000,000 BC to 5,000 BC: Foraging, in which population doubled every 250,000 years.</li> <li>5,000 BC to 1600 AD: Farming, in which population doubled every 1,000 years.</li> <li>1600 AD to present: Industry, in which GDP doubled every 15 years.</li> </ol> <p>These numbers are approximate, of course. Hanson also notes that each transition to the next era took less than a doubling time of the previous era. E.g. industry replaced farming as the dominant growth mode in less than the doubling time of farming (1,000 years).</p> <p>If one extrapolates the numerological trend (admittedly, an absurdly weak argument), the next era after ours would have an economic doubling time on the order of months or weeks. This sounds crazy. How could a 200x speedup in economic growth <em>possibly</em> happen? What would such a world look like? <em>Age of Em</em> is Hanson’s attempt to answer these questions.</p> <h2 id="the-idea">The Idea</h2> <p>Today, economic growth is bottlenecked by people. Machines can be mass-produced, but people take decades to mature and learn skills. It’s possible to make more machines per worker, but one quickly runs into diminishing returns. Someone with 10 laptops or 10 bulldozers won’t be 10x as productive.<sup id="fnref:bottleneck"><a href="#fn:bottleneck" class="footnote">2</a></sup> To speed-up economic growth by 200x, the bottleneck must be removed. Something must substitute for human intelligence.</p> <p>When considering substitutes for human intelligence, most people’s thoughts turn to artificial intelligence. But Hanson is pessimistic about the arrival of de-novo AI. He thinks it is more likely that <a href="">brain emulations</a> will come first.<sup id="fnref:ai"><a href="#fn:ai" class="footnote">3</a></sup> (The “em” in <em>Age of Em</em> is short for “emulation”.) Creating such ems requires three key technologies, and none of them exist today:</p> <ol> <li>Fast, cheap computers.</li> <li>High-resolution scans of one or more human brains.</li> <li>Accurate models of all relevant cell types in the brain.</li> </ol> <p>Hanson doesn’t give any concrete timeline for when these technologies will exist. He only says “some time in the next century”. Fortunately, none of his analysis depends on when ems become feasible, just that they arrive before AI.</p> <p>Once ems are made, they’ll differ from us in several ways:</p> <ol> <li>Ems are immortal…-ish. So long as their hardware is maintained and powered, they can live indefinitely. This isn’t as great as it sounds. Today’s cars and houses are just as “immortal”.</li> <li>Ems can run at different speeds. Faster ems cost more to run, similar to how faster cloud servers cost more.</li> <li>Ems can “teleport” by transmitting their mind-state across a network. If latency is low enough, they need only to transmit their input and output signals.</li> <li><strong>Ems can be copied.</strong> Many consequences stem from this one difference.</li> </ol> <p>What makes <em>Age of Em</em> interesting is that it rigorously explores the consequences of ems, and that it does so by applying standard scientific models. There’s no hand-waving or contrarianism. The only unusual thing is the question being asked: “What would things be like in an em world?”</p> <h2 id="my-observations">My Observations</h2> <blockquote> <p>Seen up close and honestly, I expect the future usually to look like most places: mundane, uninspiring, and morally ambiguous, with grand hopes and justifications often masking lives of quiet desperation. Of course, lives of quiet desperation can still be worth living.<br /> – Robin Hanson, <em>Age of Em</em></p> </blockquote> <p>Reading <em>Age of Em</em> opened my eyes to how sloppy most futurism is. The field is filled with incomplete analyses and moralizing about the present day. In contrast, <em>Age of Em</em> treats the future like a real place. To use language from <a href="">construal level theory</a>: It kept me thinking in near-mode. I was pleased by the broad range of topics covered. These included: thermodynamics, software engineering, reversible computing, surveillance, city planning, language, and charity. No matter one’s interests, there’s something to engage with.</p> <p>Two specific parts of the book captivated me. They were software-related, of course. One section described the life of a software engineer:</p> <blockquote> <p>For software engineering tasks where parallel software and tools suffice, and where the software doesn’t need to interact with slower physical systems, em software engineers could be productive even when sped up to the top cheap speed. This often makes it feasible to avoid the costs of coordinating across many engineers, by having a single engineer spend an entire subjective career creating a large software system. For an example, an engineer that spent a subjective century at mega-em speeds would complete this period in less than 1 objective hour. Thus when such a delay is acceptable, parallel software may be written by a single engineer taking a subjective career length.</p> </blockquote> <p>This scenario may seem absurd, but it’s a decent prediction of what will happen in a world where minds can be copied and run at different speeds. While <em>you</em> may not want to live such a life, there are some people who will choose it. Those minds will dominate the em economy.</p> <p>Another section briefly discussed software rot. That is: Adapting mature software to new circumstances requires more time and effort than creating new software from scratch. Open source software has <a href="/2017/02/28/software-rot/">tons of examples of this</a>.</p> <p>Hanson claims to be applying standard models and theories to his em scenario, but I don’t know enough social science to tell if that’s true. When the text entered my areas of expertise (computer science, software engineering), I found nothing objectionable. Also, I haven’t heard any domain experts disputing his claim, so I’d bet money that Hanson correctly applied standard theories to this scenario.</p> <p>I’m not sure if the author intended it, but the text works well as an ebook. There are plenty of references and links to related chapters, so I had no problem jumping around. Many footnotes contained URLs, making it easy to track down more info on conclusions I was more skeptical about. I wish more ebooks took advantage of the medium in these ways.</p> <h2 id="my-criticisms">My Criticisms</h2> <blockquote> <p>In sum, even though many critics have reasonable points, I still think the analysis in this book was worth the effort.<br /> – Robin Hanson, <em>Age of Em</em></p> </blockquote> <p>While the ideas fascinated me, the writing itself was rather matter-of-fact. It wasn’t as dry as an academic paper, but neither was it particularly compelling. This could be taken in a positive light. It means the book succeeds on its ideas alone, not just due to fancy writing. And it’s not all dry. The penultimate chapter –on policy recommendations– uses more emotionally stirring language.</p> <p>When it comes to <em>Age of Em</em>’s core ideas, I can’t find any major flaws. To dispute the book requires either rejecting Hanson’s core assumptions or rejecting widely-accepted scientific models. The book contains so much detail that it would be easy to nitpick, but such pedantry is tiresome to read and to write.</p> <p>In my opinion, the weakest part of <em>Age of Em</em> is the assumption that em minds won’t be very tweakable. To be fair, I think it’s a valid simplifying assumption. The book is a straightforward, first-cut analysis. Complicating the base assumptions would have made for an intractable project. Still, one should not be very confident about how tweakable brain emulations can be. And even if most tweaks are hard, there may exist a few easy tweaks which could create a world we find utterly abhorrent. I’d really like to know what neuroscience has to say about this.</p> <h2 id="conclusion">Conclusion</h2> <blockquote> <p>…many of your ancestors would be tempted to disown you, if they were told many things about you. While they’d be pleased and impressed by many of your features, other things about you might horrify them.<br /> – Robin Hanson, <em>Age of Em</em></p> </blockquote> <p>When examined closely, the world described in <em>Age of Em</em> doesn’t sound so bad to me. Ems will be smarter, healthier, and harder working than almost everyone today. They’ll live long and fulfilling lives. Compared to our civilization, theirs will be larger, more capable, and more robust.</p> <p>I think many detractors neglect that last adjective: robust. Existential risk is a crucial consideration. Hanson notes that it would be very hard to eradicate ems. Also, sped-up ems could monitor nanotech or AI experiments and react far more quickly than humans. Even if one thinks an em world is less desirable than ours, the reduction in existential risk may be worth it.</p> <p>Lastly: As positive as my review is, I must admit that <em>Age of Em</em> will only interest a small subset of people. Fortunately, most people reading this will qualify.</p> <hr /> <div class="footnotes"> <ol> <li id="fn:eras"> <p><a href="">Long-Term Growth As A Sequence of Exponential Modes</a> <a href="#fnref:eras" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:bottleneck"> <p>You might ask, “If people are the bottleneck for economic growth, and population doesn’t double every 15 years, then how does our economy do that?” The answer is that much of today’s economic growth comes from making <em>better</em> machines. <a href="#fnref:bottleneck" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:ai"> <p>Hanson backs this up with supporting evidence &amp; reasoning in the book. A shorter version is in a blog post titled <em><a href="">AI Progress Estimate</a></em>. <a href="#fnref:ai" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> Bikepacking: The Idaho Hot Springs Loop 2016-07-22T16:48:55-07:00 <p>I recently rode the Idaho Hot Springs loop with my dad &amp; my uncle. In nine days, we traveled 510 miles and climbed 37,000 feet. It was rather enjoyable.</p> <p>Read <a href="">my dad’s write-up</a> for all the details. You can also view <a href="/photos/idaho_hot_springs_loop_2016/">my photo gallery of the trip</a>.</p> <p>For those who care to see where we went, I tracked the entire route on Strava:</p> <ul> <li>Day 1: <a href="">McCall to Warm Lake</a></li> <li>Day 2: <a href="">Warm Lake to Stanley</a></li> <li>Day 3: <a href="">Stanley to Ketchum attempt 1. My dad’s derailleur broke.</a></li> <li>Day 3: <a href="">Stanley to Ketchum attempt 2. Started at 4:30PM.</a></li> <li>Day 4: <a href="">Ketchum to Featherville</a></li> <li>Day 5: <a href="">Featherville to Cottonwood campground</a></li> <li>Day 6: <a href="">Cottonwood campground to Idaho City</a></li> <li>Day 7: <a href="">Idaho City to Trail Creek campground</a></li> <li>Day 8: <a href="">Trail Creek campground to Cascade</a></li> <li>Day 9: <a href="">Cascade to McCall</a></li> </ul> <p>Lastly, this trip caused me to break <a href="/2015/01/07/burnout-is-in-the-mind/">my GitHub streak</a>. I brought <a href="/2015/04/19/2015-macbook-review/">my laptop</a>, but most nights I was too tired to do anything. At the end, my streak had been going for 1280 days. That’s 3 years, 6 months, and 3 days. Or put another way: over 10% of my life. I don’t know if I’ll ever exceed that, but I’ve already gotten back in the groove.</p> Interesting Tech that is Just Around the Corner 2016-05-14T17:36:23-07:00 <p>When talking about near-future technologies, much of the discussion surrounds stuff like self-driving cars and <a href="">CRISPR</a>. Rarely do people notice the more modest things that are both closer to fruition and more likely to be brought to market. Allow me to provide some examples.</p> <h2 id="vr-with-eye-tracking">VR with Eye Tracking</h2> <p>VR is becoming commercially feasible, but few have paid attention to how it can be improved with <a href="">eye-tracking</a>. It may seem like a minor addition, but it’s not just a joystick-like input. Eye-tracking allows for far more interesting VR experiences.</p> <p>Imagine this technology being used in a VR <a href="">Silent Hill</a> or <a href="">Resident Evil</a>. You put the headset on and start playing. You see something move in your peripheral vision, but by the time your eyes have <a href="">saccaded</a>, it’s gone. No matter how hard you try, you can’t get a good look at it. With only hints and sounds to go on, your imagination fills in the rest.</p> <p>Such a game would be –without a doubt– the scariest game <em>ever</em>. I can’t wait to play it.</p> <h2 id="paralympics">Paralympics</h2> <p>It’s likely that some Paralympic records will soon exceed their Olympic counterparts. At top speed, the best below-the-knee prosthetics are more efficient than natural legs.<sup><a href="#ref_1">[1]</a></sup> So why haven’t the records already fallen? Several reasons:</p> <ul> <li>Compared to able-bodied athletes, the talent pool of below-the-knee amputee athletes is miniscule. Oscar Pistorius was in the top 0.1% of that group. Usain Bolt is in the top 0.000001% of able-bodied athletes.</li> <li>Runners on prosthetics take longer to accelerate to top speed, harming their performance in shorter distance events. Unfortunately, the longest Paralympic event for below-the-knee amputees is 400m.</li> </ul> <p>So the technology is here, but it’s hard to predict exactly when a Paralympic athlete will hold an overall record. It depends on a sufficiently elite athlete emerging from the talent pool (effectively a random event) and the whims of the International Paralympic Committee. I’d put even money on it happening before or at Tokyo (2020).</p> <h2 id="implantable-blood-glucose-monitors">Implantable Blood Glucose Monitors</h2> <p>1 in 12 adults worldwide have diabetes.<sup><a href="#ref_2">[2]</a></sup> Sufferers can lose limbs or even go blind. With proper blood glucose monitoring, many of these maladies can be avoided. Today, this requires pricking the skin to get a blood sample. It’s really hard to get people to cut themselves a half-dozen times a day, especially when the consequences of poor blood glucose management are years or decades away. Even then, 5-6 measurements per day doesn’t allow for very accurate management. Implantable glucose monitors solve these problems.</p> <p>Several companies have such devices in trials. It’s likely that they’ll be publicly available in a few years.</p> <h2 id="conclusion">Conclusion</h2> <p>There are so many inventions that will improve our lives. Most of them won’t make the news. Most of them –when held in isolation– won’t fundamentally change the human condition. But they gradually accumulate, and eventually we look back and think, “Wow, stuff sure was primitive back in the day.”</p> <p>Don’t forget that.</p> <hr /> <ol> <li> <p><span id="ref_1"></span> <a href="">Wikipedia: The Mechanics of Oscar Pistorius’ running blades</a></p> </li> <li> <p><span id="ref_2"></span> <a href="">Wikipedia: Epidemiology of diabetes mellitus</a></p> </li> </ol> Warrantless Fingerprinting 2016-03-18T23:24:34-07:00 <p>Imagine a world in which the police needed a warrant to dust for latent fingerprints. That is, after a crime is discovered or reported, the police have to go to a judge and demonstrate probable cause that person X is involved. If the judge agrees, a fingerprint warrant is issued. Only then can the police dust the crime scene for fingerprints, and the only information they’re allowed to use is whether X’s fingerprints are present.</p> <p>It would be a world much like this one, except criminals would be caught less often.</p> <p>Now imagine living in that world and trying to convince others that the country would be better-off if police <em>didn’t</em> need a warrant to dust for fingerprints. Yes, you admit, there’s a chance that some innocent peoples’ privacy could be infringed, but more criminals would be brought to justice. And with more fingerprints, prosecutors wouldn’t have to rely on flimsier evidence such as eyewitness testimony. In addition to convicting more criminals, this could spare innocent people from prison. In short: we could reduce crime, save lives, and make justice more just.</p> <p>Is there any doubt that despite your benevolent intentions, you would be branded a fascist? After all, you are a proponent of <em>warrantless fingerprinting</em>. Many of your friends and peers would think less of you for that. If you had any fame, you would likely be hounded by the <a href="">ACLU</a> and the <a href="">EFF</a>. Despite being sincere in your views and using straightforward reasoning, people would continually misrepresent you as an authoritarian who hates privacy.</p> <p>Hopefully, this is starting to sound familiar.</p> <p>Our current legal system is the product of many historical accidents. In some circumstances, it may give too much leeway to police and prosecutors. In others, it may give too little. Reasonable, intelligent people can come to different conclusions about this. Those in favor of warrantless X are not authoritarian or fascistic. Those against warrantless X are not paranoid anarchists. So please tone down the rhetoric and <a href="/2015/03/25/please-stop-getting-outraged/">stop getting outraged</a>.</p> On Learning C, Part 4: What Should I Read? Why Should I believe you? 2016-02-10T22:30:00-08:00 <h3 id="table-of-contents">Table of Contents</h3> <ul> <li><a href="/2016/01/04/on-learning-c-part-1-k-r/">Part 1: K&amp;R</a></li> <li><a href="/2016/01/18/on-learning-c-part-2-zed-shaws-learn-c-the-hard-way/">Part 2: Zed Shaw’s Learn C the Hard Way</a></li> <li><a href="/2016/02/04/on-learning-c-part-3-c-programming-substance-guidelines/">Part 3: C Programming Substance Guidelines</a></li> <li><a href="/2016/02/10/on-learning-c-part-4-so-what-should-i-read/">Part 4: What Should I Read? Why Should I believe you?</a> (You are here.)</li> </ul> <hr /> <h2 id="why-should-i-believe-you">Why should I believe you?</h2> <p>When it comes to C, I am quite proficient. I’ve been employed professionally to write C. I created <a href="/ag/">a somewhat popular open source project in C</a>. I have extensive experience profiling C programs<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup><sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup>, optimizing them<sup id="fnref:3"><a href="#fn:3" class="footnote">3</a></sup><sup id="fnref:4"><a href="#fn:4" class="footnote">4</a></sup>, and making them multithreaded<sup id="fnref:5"><a href="#fn:5" class="footnote">5</a></sup>. I’ve contributed to other open source C projects. In short, if I’m not worth taking seriously on this topic, then very few people are.</p> <h3 id="how-i-learned-c">How I Learned C</h3> <p>C was my first real programming language.<sup id="fnref:6"><a href="#fn:6" class="footnote">6</a></sup> I was introduced to it at the age of 13. Thanks to some luck and an advanced placement test, I was allowed to take up to two classes per semester at <a href="">Gonzaga University</a>. Wanting to learn more about programming, I enrolled in CS121.</p> <p><br /></p> <p><img alt="My student ID" src="/images/student_id.jpg" style="width: 512px; height: 330px;" /></p> <p>I stuck out a little on campus.</p> <p><br /></p> <p>I distinctly remember an early assignment where I was completely stumped by a bug. I’d almost finished the program, but there was one issue that I couldn’t fix. An <code>if</code> statement was always evaluating to <code>TRUE</code>, even when it shouldn’t. The <code>else</code> was never taken. The program compiled without warnings. It was incredibly frustrating.</p> <p>I spent <em>two days</em> staring at that code. I didn’t know about debuggers, so I peppered my code with <code>printf()</code>s. I commented and uncommented chunks of code. No matter what I tried, I simply couldn’t understand why the program was misbehaving. I was almost in tears when I asked my dad for help. He saw the problem in seconds:</p> <figure class="highlight"><pre><code class="language-c" data-lang="c"><span></span><span class="k">if</span> <span class="p">(</span><span class="n">a</span> <span class="o">=</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span></code></pre></figure> <p>I had a single equals in a conditional. That meant I was assigning <code>a</code> to <code>b</code> instead of comparing them. As soon as I added another equals, my program worked flawlessly. All that effort and frustration was caused by a single missing character.<sup id="fnref:7"><a href="#fn:7" class="footnote">7</a></sup></p> <p>I’m still surprised that, afterwards, I remained interested in writing code. I’ve quoted him before, but <a href="">Douglas Crockford</a> <a href="">said it best</a>:</p> <blockquote> <p>I think there has to be something seriously wrong with you in order to do this work. A normal person, once they’ve looked into the abyss, will say, “I’m done. This is stupid. I’m going to do something else.” But not us, ‘cause there’s something really wrong with us.</p> </blockquote> <p>This was undoubtedly the most difficult educational experience of my life. I really did learn C the hard way.</p> <h2 id="so-what-should-i-read">So what should I read?</h2> <p>Honestly? I’m not sure. For those who want to to learn C, I have yet to find a book that I can unconditionally recommend. The only text I can personally suggest is <a href="">the Kernighan and Ritchie book</a> from <a href="/2016/01/04/on-learning-c-part-1-k-r/">part 1</a>. As I said in that post, caveats apply.</p> <p>For those who know some C and are looking to improve their skills, there are better resources. I’ve heard good things about <a href="">Robert Love</a>’s <a href=""><em>Linux Kernel Development</em></a> (<a href="">PDF</a>). And though it covers <em>much</em> more than C, <a href=""><em>Computer Systems: A Programmer’s Perspective</em></a> will teach you all the gory details of how source code gets turned into machine code.</p> <!-- There are also a few resources I haven't reviewed, bu [Modern C]( by [Jens Gustedt]( C Programming: A Modern Approach --> <p>The dearth of good C books is a bit of a bummer, but there may be a silver lining. I think many learners rely too much on books. It’s often more educational to poke around on your own. Read other people’s code. Examine open source projects. Ask others for help. And if you’re not sure how something works, <a href="/2012/01/30/programming-we-can-do-science/">do science</a>!</p> <hr /> <div class="footnotes"> <ol> <li id="fn:1"> <p><a href="/2012/01/23/making-programs-faster-profiling/">Making Ag Faster: Profiling with Valgrind</a> <a href="#fnref:1" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:2"> <p><a href="/2012/02/08/profiling-with-gprof/">Profiling with Gprof</a> <a href="#fnref:2" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:3"> <p><a href="/2015/02/08/optimizing-ag-special-casing-file-extensions/">Optimizing Ag: Special-casing File Extensions</a> <a href="#fnref:3" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:4"> <p><a href="/2012/09/03/profiling-ag-writing-my-own-scandir/">Profiling Ag. Writing My Own Scandir</a> <a href="#fnref:4" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:5"> <p><a href="/2012/09/07/the-silver-searcher-adding-pthreads/">The Silver Searcher: Adding Pthreads</a> <a href="#fnref:5" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:6"> <p>Before that, I’d only written a few toy programs in <a href="">Logo</a>, <a href="">QBasic</a>, and <a href="">TI-BASIC</a>. <a href="#fnref:6" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:7"> <p>If you’re wondering why the compiler didn’t warn about this, it’s because this happened in 1998. Back then, gcc didn’t warn about assignments in conditionals. Nowadays, any sane compiler will complain. How fortunate one is to learn C today. 🙂 <a href="#fnref:7" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> On Learning C, Part 3: C Programming Substance Guidelines 2016-02-04T22:29:02-08:00 <h3 id="table-of-contents">Table of Contents</h3> <ul> <li><a href="/2016/01/04/on-learning-c-part-1-k-r/">Part 1: K&amp;R</a></li> <li><a href="/2016/01/18/on-learning-c-part-2-zed-shaws-learn-c-the-hard-way/">Part 2: Zed Shaw’s Learn C the Hard Way</a></li> <li><a href="/2016/02/04/on-learning-c-part-3-c-programming-substance-guidelines/">Part 3: C Programming Substance Guidelines</a> (You are here.)</li> <li><a href="/2016/02/10/on-learning-c-part-4-so-what-should-i-read/">Part 4: What Should I Read? Why Should I believe you?</a></li> </ul> <hr /> <h2 id="c-programming-substance-guidelines">C Programming Substance Guidelines</h2> <p>A few months ago, another C guide <a href="">was posted on Hacker News</a>: <a href="">C Programming Substance Guidelines</a>. I disagreed with some of its recommendations, including the endorsement of Shaw’s <em>Learn C the Hard Way</em>, so I left a comment on the HN submission. In hindsight, I see that my comment was too dismissive and curt. Fortunately, the author didn’t take it personally. In fact, he was interested in a more detailed critique. That’s the purpose of this post.</p> <p>What follows is a sort of shotgun approach. I’ve quoted and responded to the guidelines that I think are particularly important to follow (or not follow). And in some cases, I present a more nuanced version of the author’s advice, so as to diffuse some ways in which it could backfire. Alright, on with the show…</p> <h3 id="codebase-size">Codebase Size</h3> <blockquote> <p>Things that are large and frequently changing will <strong>never</strong> be secure. If you care about security, the best thing you can do is keep the project small.</p> </blockquote> <p>This is great advice. It applies to all bugs, not just security issues. After a half-century of research into software development, the best predictor of a codebases’s bug count is still lines of code. Even when researchers try to find correlations with more advanced metrics, it reduces to lines of code:</p> <blockquote> <p>For nonheader files, all the metrics show a high degree of correlation with lines of code. We accounted for the confounding effect of size, showing that the high correlation coefficients remain for different size ranges. In our opinion, there is a clear lesson from this study: syntactic complexity metrics cannot capture the whole picture of software complexity. Complexity metrics that are exclusively based on the structure of the program or the properties of the text (for example, redundancy, as Halstead’s metrics do), do not provide information on the amount of effort that is needed to comprehend a piece of code—or, at least, no more information than lines of code do.<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup></p> </blockquote> <p>Be warned though, <a href="/2013/03/06/the-cost-of-features/">it is very hard to keep a codebase small</a>.</p> <h3 id="setting-pointers-to-null-after-free">Setting Pointers to <code>NULL</code> After <code>free()</code></h3> <blockquote> <p>Immediately clear pointers after freeing…</p> </blockquote> <p>I think this advice is dangerously double-edged. It really depends on what you’re doing. If you intend to reuse the pointer, definitely set it to <code>NULL</code> after <code>free()</code>ing. In that case, the pointer serves as both a pointer and as a flag for related parts of the program’s control flow. I recommend this pattern as it makes it very hard to get into an invalid state. Either the pointer points to a valid object, or it’s <code>NULL</code>.</p> <p>On the other hand: If you intend for the pointer to be allocated and deallocated only once, clearing it just hides bugs. If your program’s control flow has unexpected behavior that results in a double-free, it’s important to find out why that’s happening. Papering over it with <code>ptr = NULL;</code> will fix the symptom, but it won’t fix the underlying cause.</p> <h3 id="calloc-vs-malloc"><code>calloc()</code> vs. <code>malloc()</code></h3> <blockquote> <p>Use <code>calloc</code> instead of <code>malloc</code></p> </blockquote> <p>I don’t think this matters much, but I mildly disagree. Like the previous example, this will likely hide the underlying cause of bugs in your program. If an issue is “fixed” by <code>calloc()</code>, that means something wasn’t properly initialized. Zeroing-out the entire memory region might be the correct way to initialize it, or it might not. It really depends on what you’re doing. Instead of blindly zeroing-out everything, it’s better to explicitly initialize memory to the values you want. Doing so will help you avoid a class of bugs that –while rare– are very subtle and pernicious.</p> <h3 id="custom-allocators">Custom Allocators</h3> <blockquote> <p>Don’t write custom allocators</p> </blockquote> <p>I hardly ever come across these, but I certainly agree. Unless you <em>really</em> know what you’re doing, a custom allocator will likely be buggy and slow. It will also make it harder for other programmers to understand your code. I’ve never needed to write my own allocator. If memory allocation/deallocation becomes a performance bottleneck, use an existing library such as <a href="">APR’s memory pools</a>.</p> <h3 id="braces">Braces</h3> <p>Several guidelines reference brace style:</p> <blockquote> <p>Single line if possible: <code>if(rc &lt; 0) return rc;</code></p> </blockquote> <blockquote> <p>Single line if possible: <code>if(X == rc) return Y;</code></p> </blockquote> <blockquote> <p>Put one-statement conditionals on the same line as the condition</p> </blockquote> <blockquote> <p><code>if(rc &lt; 0) goto fail;</code></p> </blockquote> <p>I can’t get behind that. Never omit braces. The reasoning behind this is straightforward: When changing a one-line conditional into a multi-line conditional, people occasionally forget to add braces. Often, a <code>goto</code> or <code>return</code> ends up always being taken. By always using braces, you make your programs immune to this entire class of bugs. It’s a no-brainer. You’re sacrificing subjective improvement in appearance for an objective improvement in correctness. I can’t say it enough: Never omit braces.</p> <h3 id="error-handling">Error Handling</h3> <blockquote> <ul> <li>Error handling</li> <li>Do it, always, even in sample code<br /> … <ul> <li>Handle errors like everyone is watching</li> </ul> </li> </ul> </blockquote> <p>This seems needlessly paranoid. Both the “when” and “how” of error handling depend heavily on what you’re doing. If your code is used (or can be used) in something important, then go wild dealing with different return values. However, there are some errors that you should probably never try to handle. For example, according to the spec, <code>malloc()</code> will return <code>NULL</code> if it couldn’t allocate the requested memory. In practice, this is almost never the case. Modern operating systems lie about having enough memory. According to <a href="">the Linux <code>malloc</code> manpage</a>:</p> <blockquote> <p>By default, Linux follows an optimistic memory allocation strategy. This means that when <code>malloc()</code> returns non-<code>NULL</code> there is no guarantee that the memory really is available.</p> </blockquote> <p>After lying to your process, the OS will then <a href="">kill it for accessing the “allocated” memory</a>. It’s a similar story for OS X, FreeBSD, and others. Considering these behaviors, it makes very little sense to handle <code>malloc()</code> errors. Only the most mission critical code needs to be so robust. For most programs, it’s fine to just crash. If you like, you can make the error message nicer by <a href="">wrapping <code>malloc()</code> in a check that <code>exit()</code>s with a nonzero value</a>.</p> <p>That said, I think this guideline has a kernel of truth. C programs written by beginners tend to have issues with error handling. Often, they completely ignore errors and keep on truckin’, causing them to crash in odd ways. A simple crash-and-burn check would do wonders. Something like:</p> <figure class="highlight"><pre><code class="language-c" data-lang="c"><span></span><span class="n">rv</span> <span class="o">=</span> <span class="n">do_something</span><span class="p">(</span><span class="o">&amp;</span><span class="n">foo</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">rv</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&quot;Error: %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">strerror</span><span class="p">(</span><span class="n">errno</span><span class="p">));</span> <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="p">}</span></code></pre></figure> <p>(This assumes <code>do_something()</code> sets <code>errno</code>.)</p> <h2 id="conclusion">Conclusion</h2> <p>Overall, I think <em>C Programming Substance Guidelines</em> is helpful, but I can’t point newbies to it without major caveats. A decent portion of its advice is double-edged or counterproductive. My initial thoughts on the guide are a good note to end on:</p> <blockquote> <p>Please don’t blindly follow this guide. Explore other codebases (including the ones the author linked to). Talk to other programmers. Write your own projects, and get feedback from those who are more knowledgable.</p> </blockquote> <blockquote> <p>You might notice that this advice generalizes to every language. That’s because C isn’t special. If anything, the language itself is simpler than most. C has just had more time to accumulate cruft, both technical and cultural. So don’t feel intimidated. Once you learn those bits of historical trivia, you’ll be fine.</p> </blockquote> <hr /> <div class="footnotes"> <ol> <li id="fn:1"> <p><a href=""><em>Making Software: What Really Works, and Why We Believe It</em></a>, Chapter 8 (by Israel Herraiz &amp; Ahmed E. Hassan) <a href="#fnref:1" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> On Learning C, Part 2: Zed Shaw's Learn C the Hard Way 2016-01-18T22:26:52-08:00 <h3 id="table-of-contents">Table of Contents</h3> <ul> <li><a href="/2016/01/04/on-learning-c-part-1-k-r/">Part 1: K&amp;R</a></li> <li><a href="/2016/01/18/on-learning-c-part-2-zed-shaws-learn-c-the-hard-way/">Part 2: Zed Shaw’s Learn C the Hard Way</a> (You are here.)</li> <li><a href="/2016/02/04/on-learning-c-part-3-c-programming-substance-guidelines/">Part 3: C Programming Substance Guidelines</a></li> <li><a href="/2016/02/10/on-learning-c-part-4-so-what-should-i-read/">Part 4: What Should I Read? Why Should I believe you?</a></li> </ul> <hr /> <p>Another common answer to, “What book should I read to learn C?”, is <a href="">Zed Shaw</a>’s <a href=""><em>Learn C the Hard Way</em></a>, AKA “LCTHW.”</p> <h2 id="learn-c-the-hard-way-a-flawed-text-with-an-agenda">Learn C the Hard Way: A Flawed Text with an Agenda</h2> <p>As harsh as that title may sound, I’m really not trying to court controversy. I have no grudge with Zed Shaw. In fact, I think he’s a talented programmer and an excellent teacher. He has helped thousands of people with his guide, <a href=""><em>Learn Python the Hard way</em></a>. He has done far more to advance programming education than I could ever hope to. It is for these reasons that I wish I could say, “<em>Learn C the Hard Way</em> is worth reading.” Unfortunately, it’s not.</p> <p>I’m not alone in this view. The most well-known (though in my opinion, flawed) criticism of LCTHW is <a href="">Learn C the Wrong way</a> by Tim Hentenaar. While snarky and hostile, it does contain valid criticisms. The chapter on setup is quite poor. The chapter on invoking the compiler is atrocious. It only talks of <code>make</code>, not directly invoking <code>gcc</code> or <code>clang</code>. In essence, it pretends there is only one way to invoke the compiler: a build system, and only one build system: <code>make</code>. I’m all for introductory texts keeping things simple, but that’s going too far. I could list dozens of other problems, but I’d largely be duplicating Hentenaar’s efforts. In short, there’s no salvaging this book.</p> <p>If I could distill my evaluation of LCTHW to one sentence, it would be: Shaw fundamentally disagrees with the majority of C programmers about how to write C. The biggest divergence comes from his condemnation of NULL-terminated strings. Originally, LCTHW had <a href="">an introductory chapter “critiquing” K&amp;R</a>. Much of the chapter boils down to: If you don’t NULL-terminate something that’s supposed to be NULL-terminated, all kinds of terrible things can happen. I’m not sure who this warning is intended for. Anyone who writes C will quickly have this knowledge burned into their brain. When it comes to details, Shaw’s critique is full of mistakes. Instead of listing them all, I’ll just link to the times it has been discussed on Hacker News: <a href="">1</a>, <a href="">2</a>, <a href="">3</a>, <a href="">4</a>. Take a look at <a href="">Shaw’s replies</a>. They make my case far better than I could.</p> <h2 id="shaws-response">Shaw’s Response</h2> <p>Shaw eventually received enough criticism that he <a href="">admitted defeat and removed the K&amp;R chapter</a>. In that blog post, he went on to disparage the entire C community and the language itself:</p> <blockquote> <p>But C? C’s dead. It’s the language for old programmers who want to debate section A.6.2 paragraph 4 of the undefined behavior of pointers. Good riddance. I’m going to go learn Go.</p> </blockquote> <p><a href="">Shaw’s response to Tim Hentenaar</a> had the same tact and grace. Honestly, I find Shaw’s response baffling. He spends very few words addressing technical arguments. Most of the post is Shaw saying good things about himself and bad things about Tim Hentenaar. Tim lacks qualifications. Tim doesn’t understand how to teach code. Tim is arrogant. Tim is hubristic. Tim can’t spell. Those may all be true, but they don’t address the arguments. Yes, Tim is a snarky prick, but that doesn’t make his arguments incorrect.</p> <p>There’s only one criticism that Shaw really addresses, and that’s Hentenaar’s defense of NULL-terminated strings. Shaw shows how Hentenaar’s <code>copy()</code> could fail… if the source string is corrupted. As I read this part of Shaw’s post, I was reminded of a quote by Charles Babbage:</p> <blockquote> <p>On two occasions I have been asked, “Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?” … I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question.<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup></p> </blockquote> <p>If you’re willing to posit corrupt or invalid inputs to a function, all bets are off. No data structure will save you. Amusingly, Shaw’s original criticism of Hentenaar’s <code>copy()</code> was incorrect. On the one technical issue Shaw engaged with, he was mistaken. Someone else had to correct him. That’s quite the indictment of his C knowledge. If Shaw can’t correctly refute one C example, what are the chances he’s written a quality book on the language?</p> <h2 id="why-im-writing-this">Why I’m Writing this</h2> <p>I have no dog in this fight. I just don’t want newbies to be misinformed.<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup> As I said before, Zed Shaw’s guides have helped thousands. But when it comes to C, he is both mistaken and more than a little arrogant. I truly wish it were otherwise.</p> <hr /> <div class="footnotes"> <ol> <li id="fn:1"> <p><a href="">Passages from the Life of a Philosopher</a> <a href="#fnref:1" class="reversefootnote">&#8617;</a></p> </li> <li id="fn:2"> <p>In fact, I knew nothing about LCTHW or this spat until <a href="">someone asked for “peer reviews”</a> of LCTHW in <a href="">/r/C_Programming</a>. <a href="#fnref:2" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> On Learning C, Part 1: K&R 2016-01-04T21:38:43-08:00 <h3 id="table-of-contents">Table of Contents</h3> <ul> <li><a href="/2016/01/04/on-learning-c-part-1-k-r/">Part 1: K&amp;R</a> (You are here.)</li> <li><a href="/2016/01/18/on-learning-c-part-2-zed-shaws-learn-c-the-hard-way/">Part 2: Zed Shaw’s Learn C the Hard Way</a></li> <li><a href="/2016/02/04/on-learning-c-part-3-c-programming-substance-guidelines/">Part 3: C Programming Substance Guidelines</a></li> <li><a href="/2016/02/10/on-learning-c-part-4-so-what-should-i-read/">Part 4: What Should I Read? Why Should I believe you?</a></li> </ul> <hr /> <p>C is an important language for many reasons. It’s ubiquitous. No other language runs on as many platforms. It’s <em>fast</em>. It gets you closer to the bare metal than anything but assembly. It’s old. It has a long history, much of it intertwined with the beginnings of UNIX.</p> <p>It also has a reputation for being hard to master.</p> <p>When novices ask, “What book should I read to learn C?”, I’ve heard a common recommendation: <a href="">Kernighan</a> &amp; <a href="">Ritchie</a>’s <a href=""><em>The C Programming Language</em></a>, AKA “the K&amp;R book.” Unfortunately, I can’t recommend it to beginners. Allow me to explain why.</p> <h2 id="kr-decent-but-dated">K&amp;R: Decent, but Dated</h2> <p>The K&amp;R book does an excellent job of explaining the C language. It describes syntax, keywords, program structure, preprocessor behavior, and the standard library. There’s just one problem: it’s <em>old</em>. The last major update was in 1988. This leads to amusing anachronisms, such as the intro to a section about function arguments:</p> <blockquote> <p>One aspect of C functions may be unfamiliar to programmers who are used to some other languages, particularly Fortran. In C, all function arguments are passed “by value.”<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup></p> </blockquote> <p>Humor aside, the book’s age does hurt its educational value. Omissions include:</p> <ul> <li><code>//</code>-style comments</li> <li><a href="">Inline functions</a></li> <li><code>snprintf()</code></li> <li>Types such as <code>bool</code> and <code>long long</code></li> <li>Variable-length arrays</li> <li><a href="">Variadic macros</a></li> </ul> <p>It’s not essential for beginners to know these features, but a book about C should at least mention them. K&amp;R also avoids any discussion of build systems (autotools), debuggers (gdb, lldb), or profilers (gprof, dtrace). That’s more understandable though. These tools either didn’t exist or were in their infancy when the book was authored. Considering how dated those sections would now be, it’s probably good that they’re missing.</p> <p>I think Kernighan &amp; Ritchie never had the goal of covering anything outside the language itself. And that’s the main reason why I can’t recommend K&amp;R to beginners. It lacks any sort of “getting started” section. It has no guides for setting up a development environment. There’s no chapter on how to install and use a compiler. Again, I realize these sections would be completely out-of-date had they existed in the 1988 book. Still, it’s important that programming language books help users set up development environments.</p> <p>In short: K&amp;R is part of a solid intro to C, but it’s not enough. It needs a few updates to reflect modern C. More importantly, it needs a companion book to cover setup and tooling. In its current form, it serves as more of an overview and reference.</p> <hr /> <div class="footnotes"> <ol> <li id="fn:1"> <p>Section 1.8: Arguments – Call by value. For those who may not know: Today, pass by value is the most popular design in modern languages. <a href="#fnref:1" class="reversefootnote">&#8617;</a></p> </li> </ol> </div> FSEvents Tools: Watch a Directory for Changes 2015-12-25T08:35:18-08:00 <p>Often, when I modify files in a directory, I want some action to happen afterwards. For example: If I’m editing some source code locally, I might want it to be rsynced to a remote server. Or maybe I want to regenerate CSS after changing some <a href="">LESS</a> or <a href="">SASS</a>, or minify some JavaScript after changing the uncompressed source. Sometimes, there’s an application-specific solution to this problem. Sometimes, there isn’t. In the latter case, it would be nice to fall back on a general purpose tool.</p> <p>On Linux, this is a solved problem. Just install <a href=""><code>inotify-tools</code></a> and wrap it with a couple of scripts. Sadly, each operating system has its own unique API for monitoring filesystem changes. That means Windows and Mac users are out of luck.</p> <p><a href="/fsevents/"><code>fsevents-tools</code></a> is my attempt to solve this problem for OS X. As the name implies, it uses OS X’s <a href="">FSEvents API</a> to monitor filesystem changes. The first release (v1.0) consists of three commands:</p> <h3 id="notifywait">notifywait</h3> <p><code>notifywait</code> is a simple tool that the other utilities depend on. It does one thing: Given path(s) to watch, it waits until something in them changes and exits. For example, if you have public file sharing enabled and you’re expecting an incoming file, run:</p> <figure class="highlight"><pre><code class="language-text" data-lang="text"><span></span>% notifywait ~/Public/Drop\ Box &amp;&amp; say &quot;Dropbox changed&quot;</code></pre></figure> <p>The output will be something like…</p> <figure class="highlight"><pre><code class="language-text" data-lang="text"><span></span>Path is /Users/ggreer/Public/Drop Box Watching /Users/ggreer/Public/Drop Box Change 18158642688910021128 in /Users/ggreer/Public/Drop Box/untitled folder, flags 131328 - matched directory, notifying</code></pre></figure> <p>…followed by your computer talking. Note: <code>notifywait</code> will also exit if a file or directory is moved or deleted. In this specific example, that’s probably more than you want.</p> <h3 id="notifyloop">notifyloop</h3> <p><code>notifyloop</code> takes a <code>path</code> and a <code>command</code>. When something in <code>path</code> changes, it runs <code>command</code>. For example, if you have a bunch of LESS in <code>styles/</code> and you want to rebuild CSS when they change, you’d do something like this:</p> <figure class="highlight"><pre><code class="language-text" data-lang="text"><span></span>ggreer@carbon:~/code/ notifyloop styles ./ Watching styles Path is /Users/ggreer/code/ Watching /Users/ggreer/code/ Change 18158642688910117872 in /Users/ggreer/code/, flags 70656 - matched directory, notifying Running ./ lessc styles/colors.less styles/colors.css lessc styles/countdown.less styles/countdown.css lessc styles/hexagons.less styles/hexagons.css lessc styles/main-dark.less styles/main-dark.css lessc styles/main-light.less styles/main-light.css Path is /Users/ggreer/code/ Watching /Users/ggreer/code/</code></pre></figure> <p>Notice that, although <code></code> changed CSS files in <code>styles/</code>, <code>notifyloop</code> did not go into an infinite regress. That’s because <code>notifyloop</code> waits until <code>command</code> has finished before resuming monitoring changes.</p> <p>While simple, <code>notifyloop</code> is very flexible. You’ll probably use it more than the other tools.</p> <h3 id="autorsync">autorsync</h3> <p>Finally, there’s <code>autorsync</code>. It takes a <code>path</code> and a remote destination. If anything in <code>path</code> changes, it <a href="">rsyncs</a> <code>path</code> to the remote. In the following example, I copy the source for <a href="/ag/">ag</a> to my home server. Since the repo was out of date on that server, my first save of <code>decompress.c</code> causes a lengthy rsync. As expected, the second save rsyncs much faster. Here’s the command and output:</p> <figure class="highlight"><pre><code class="language-text" data-lang="text"><span></span>ggreer@carbon:~/code% autorsync ag lithium.local:code/ Watching ag Path is /Users/ggreer/code/ag Watching /Users/ggreer/code/ag Change 18158642688910848099 in /Users/ggreer/code/ag/src/decompress.c, flags 70656 - matched directory, notifying Running rsync -avz ag lithium.local:code/ building file list ... done ag/ ... sent 2882666 bytes received 52598 bytes 1174105.60 bytes/sec total size is 6612119 speedup is 2.25 Path is /Users/ggreer/code/ag Watching /Users/ggreer/code/ag Change 18158642688910848167 in /Users/ggreer/code/ag/src/decompress.c, flags 70656 - matched directory, notifying Running rsync -avz ag lithium.local:code/ building file list ... done ag/src/decompress.c sent 36800 bytes received 114 bytes 73828.00 bytes/sec total size is 6612119 speedup is 179.12 Path is /Users/ggreer/code/ag Watching /Users/ggreer/code/ag ...</code></pre></figure> <p>…and so on.</p> <p>Those who use GUI editors will likely recognize the value of <code>autorsync</code>. No longer will you have to ssh in and make changes using Vim or Emacs. Nor will you have to manually copy files or set up <a href="">sshfs</a>. With one command, everything gets synced to the remote server.</p> <p><br /></p> <p>I hope you find these tools as useful as I do. <a href="/fsevents/">Signed releases are available here</a>. The source code is on <a href="">GitHub at ggreer/fsevents-tools</a>.</p> The Case for "Pro" Browsers 2015-12-06T10:46:45-08:00 <p>Over the past few years, I’ve gradually become more frustrated with web browsers. Don’t get me wrong. Today’s browsers are faster, more stable, and more secure than ever. They have better debugging tools. They support more interesting technologies like <a href="">HTML5</a> and <a href="">WebRTC</a>. In almost every measurable way, browsers are strictly better than they used to be.</p> <p>Except one: User interfaces.</p> <p>Originally, browsers were created by developers for developers. But lately, Chrome and Firefox have focused on improving the experience for normal users. This is, on net, a good thing. The vast majority of users benefit from features like <a href="">voice search</a>, <a href="">profile synchronization</a>, <a href="">apps</a>, and fancy new tab pages. They also benefit from dangerous settings being hidden in places like <code>chrome://flags</code>.</p> <p>But not me. When running a browser for the first time, I disable a dozen features and install extensions to expose advanced behavior. I change my search engine so the Google Doodle doesn’t show up on Chrome’s new tab page. I add an extension to <a href="">restore Chrome’s presentation mode</a>.</p> <p>Still, I can’t fix every annoyance. The new tab page lacks recently-closed tabs. The developer console <a href="">requires some priming before pasting will work</a>. Pasting <code>javascript:</code> URLs in the address bar <a href="">doesn’t work</a>. Some TLS certificate errors can’t be overridden. These aren’t just UI annoyances. Some of these changes really have hurt developer productivity. And yet, I can’t fault Chrome for making these changes. They’re great for the vast majority of users.</p> <p>One browser can’t satisfy both consumers and developers. So what’s the solution? Simple: Have more than one browser. Differentiate. Use the same libraries and rendering engines, just tweak the UI to be more developer-friendly.</p>