More from David Heinemeier Hansson
I still remember how the car industry got all excited back in 2017 about how steering wheels would soon be obsolete. Every concept car then was a living room on wheels, seats facing inwards. The self-driving revolution was imminent, they said. Well, it wasn't... but now it actually is! Humans have a hard time with scenarios like this. If you promise them the moon in eight months, but don't end up delivering until eight years later, most will justifiably be skeptical that it's actually here — even in the face of gushing anecdotes and video evidence. That's the problem with delayed promises. So when Jason told me Tesla's self-driving tech was finally ready and real, I was indeed skeptical. I tried FSD as late as last year, and I didn't enjoy it much. Impressive in many ways, but too jerky. Too many interventions. How much could it really have improved in nine months or so? A lot, it turns out. We started the drive from Jason's house, and I watched him not once touch the pedals or steering wheel while we drove half an hour to the other end of town. Then repeated the feat on the way back. But that wasn't even the most impressive part. What really blew my mind was how dramatically better the fluidity of driving with FSD has become. His new Model Y anticipated the red light with the manners of a drives-for-the-queen-level chauffeur. And the way it knew exactly how to slow down to prevent a jerky movement when taking an incline into an elevated parking lot? Sublime. Elon, that son of a bitch, seems to have done it again! Proven everyone wrong. Proven me wrong. The self-driving dream has flipped from vaporware to credible near-term reality. All without LiDAR. AI really delivering on this one.
My latest love letter to Linux has been published. It's called Omarchy, and it's an opinionated setup of the Arch Linux distribution and the Hyprland tiling window manager. With everything configured out-of-the-box to give you exactly the same setup that I now run every day. My Platonic ideal of what a developer environment should look like. It's not for everyone, though. Arch has a reputation for being difficult, but while I think that's vastly overstated, I still think it's fair to say that Ubuntu is an easier landing for someone new to Linux. And that's why this exists as a sister project to Omakub — my opinionated setup for Ubuntu — and not a replacement of it. Because I do think that Hyprland deserves its reputation of being difficult! Not because the core tiling window manager is hard, but because it comes incredibly bare-boned in the box. You have to figure out everything yourself. Even how to get a lock screen or idle timing or a menu bar or bluetooth setting or... you get the idea. Omarchy is an attempt to solve for all that. To give you a default set of great, beautiful configurations for Hyprland, and installing all the common tooling you'd normally want. You could setup this, not change a thing, and you'll have exactly what I run every day. But you can also just use this as a paved path into the glorious world of Linux ricing. The flip side of Hyprland being so atomized is that it's infinitely configurable. You can really, really make it yours. No wonder its the preferred platform for r/unixporn, and even what PewDiePie picked up for his amazing Russian nuclear core build. I don't know when we'll literally get "The Year of Linux on the Desktop", but I've never been as convinced that its coming as I am now. There's enough dissent in the water. Enough dissatisfaction with both Apple and Microsoft. And between Valve going all-in on Steam on Linux (the Steamdeck runs Arch!), major creators (like PewDiePie) switching to Linux, and incredible projects like Hyprland — which offer not just a cheap visual copy of the two major commercial operating systems, but something much more unique and compelling — I think all the factors are in place for a big switch. At least among developers. But broad adoption or not, I'm in love with Linux, and thrilled to share my work to make it easier to enjoy.
The recent disconnection of the ICC's chief prosecutor, at the behest of the American administration, could not have come at a worse time for Microsoft. Just a month prior, the folks from Redmond tried to assure Europe that all was well. That any speculation Europeans could get cut off from critical digital infrastructure was just fear, doubt, and uncertainty. Then everything Europeans worried could happen happened in Hague. Oops! Microsoft's assurances met reality and reality won. That reality is that all American administrations have the power to disconnect any individual, company, or foreign government from digital infrastructure provided by American Big Tech. So in that sense, it's pointless to blame Microsoft for the sanctioning power vested in the Oval Office. But we certainly can blame them for gaslighting Europe about the risk. What's more important than apportioning blame, though, is getting out of the bind that Europe is in. The continent is hopelessly dependent on American Big Tech for even the most basic of digital infrastructure. If this American administration, or the next, decides to use its sanctioning power again, Europe is in a real pickle. And with the actions taken against the ICC in Haag, Europe would be negligent to ignore the threat. Denmark even more so. It's no secret that tensions between Denmark and the US are at a historic high. Trump keeps repeating a desire to take over Greenland by fuzzy means possible. The American intelligence services have been directed to increase their spying on Denmark and Greenland. Naturally, the Danes are spooked. They should be! Regardless of what happens with Greenland, trade negotiations, or geopolitical disagreements, though, it would suit Europe well to become digitally sovereign. That doesn't mean cutting off all American tech, but it does mean rejecting any services that can be turned off from Washington. So in terms of Microsoft, it means no more Microsoft 365, no more Teams, no more Azure. And that's exactly what the two biggest counties in Denmark have announced plans to do. Copenhagen and Aarhus just declared that they're going to get rid of Microsoft products for all their workers. The Copenhagen county is the largest employer in Denmark with over 40,000 employees. So this is a big deal! The chairman of the Copenhagen committee who pushed this forward made this comment to Danish media: If, theoretically, the relationship to the US gets worse, we could fear that Microsoft would be forced to shut everything down. That possibility exists. And if we suddenly can't access our emails or communicate via our systems, we'll be challenged. That's an understatement. Denmark is one of the most highly digitalized countries in the world. It's also one of the most Microsoft dependent. In fact, Microsoft is by far and away the single biggest dependency, so it makes perfect sense to start the quest for digital sovereignty there. But Denmark is also full of unambitious, defeatist bureaucrats who can't imagine a world without Microsoft. Just today, the IT director for The Capital Region declared it to utopian to think Denmark could ever achieve digital sovereignty or meaningfully replace Microsoft. Not even a decade would make a dent, says the director, while recognizing that if we'd done something 15 years ago, we wouldn't be in this pickle. A remarkable illustration of cognitive dissonance! Sadly, this is not an uncommon conclusion from people who work inside the belly of bureaucracies for too long. Whatever has always done too often seems like the only thing that ever could be done. But, as Mandela said, it always seems impossible until it's done. So let's get it done. Digital sovereignty isn't easy, but neither was securing a sovereign energy supply. Nor will it be to rebuild a credible defensive military. Europe needs all of it, yesterday. The bureaucrats who aren't interested in making it happen should find employment elsewhere.
Over the years, I've learned not to question inspiration. To simply let it drive when it shows up with a full tank. Quite often, I don't exactly know where we're going or even why we're going, but it's repeatedly taken me to just the right place at just the right time, so now I just hop in and say: Let's go! Case in point: Arch + Hyprland. It's been over a year since I created Omakub to smooth out my own exit path from macOS to Linux, and in the process, helped thousands of others enjoy a beautiful, preconfigured, and relatively familiar desktop experience with Ubuntu. And I continue to think this is an excellent choice for Linux, especially for first-time Mac and Windows defectors. But this weekend, I just happened to be home alone, and the hype around Arch + Hyprland got the better of me. While Ubuntu is all about being a friendly place for newcomers to Linux, Arch + Hyprland is the exact opposite: It's Linux on hard mode! At least that's the reputation, and there's certainly something to that. The Arch ISO literally just dumps you into a terminal with scarcely any direction. Just getting on the Wi-Fi requires learning the arcane command-line options for the iwctl terminal configurator. But besides iwctl, it's actually not that bad anymore. We now have a cheat code for installing Arch in the form of archinstall. It's a terminal interface for getting all the bits like picking a disk and creating the first user done in the correct order, without having to set aside an entire evening just to get the OS installed. So it didn't take long to get Arch up and running. That doesn't get you much further, though! By default, Arch is about as minimal as it gets. There's no default graphical interface. There are no niceties. Not even wget or curl by default! It really is just a bare-bones installation of Linux. But on the other hand, Arch is blessed with the AUR — a Wikipedia-style, community-maintained package management system that seems to have literally every piece of software ever released on Linux, and always in the latest version. A quarter of Omakub is trying to work around the fact that helpful tools like Alacritty or LazyGit or whatever rarely have official packages for Ubuntu, so you're left doing a lot of manual scripting to get everything a developer would want from a modern Linux setup. Not so with the AUR! So that's Arch. But Hyprland is even more hilarious. It's a tiling window manager with something as rare in the Linux world as a keen focus on aesthetics! It looks like it was written by visual artists rather than neckbeards. And it's at the core of the modern r/unixporn Linux ricing subculture. That's not the funny part, though. The funny part is how ridiculously atomized the entire thing is. Hyprland comes with absolutely nothing out of the box. No login screen, no menu bar, no notification system, no file manager, no visual settings application. Just a text-based configuration file, a wiki, and an outline on a map for how to design your own adventure. This means that if you're interested in running Hyprland, and you intend to set it all up from scratch, you're probably signing up for at least a good 10+ hours — just to install and configure everything! Now, there are some precompiled setup scripts out there already, but most of them still require you to do a ton of manual legwork before you reach that beautiful summit of a complete system. So while the downside of Arch + Hyprland is that literally every last detail requires you to make a choice and a config file to move on, it's also its upside: you can change EVERYTHING! And the core window tiling magic of Hyprland is one of the most intoxicating ways of using a computer that I've ever experienced. It looks amazing; it feels amazing (if you prefer using a keyboard instead of a mouse!). I've poured hours and hours into this quest over the weekend, and yet I'm still not even done with my first Arch + Hyprland build! My login screen looks like shit. I haven't decided on a final menu bar configuration. But what is working — the basic tiling flow and look — is so nice that the inspiration keeps driving the project forward. Which, of course, I've already decided to codify. I'm not going through all this work to set up a beautiful, preconfigured, fully-functional, out-of-the-box Arch + Hyprland combo and then not share it with anyone who's curious (and might not have 10–20 hours for this kind of side quest available in their schedule). So of course I registered a domain and found a way to draw some ASCII art: Omarchy is on the way!
More in programming
I still remember how the car industry got all excited back in 2017 about how steering wheels would soon be obsolete. Every concept car then was a living room on wheels, seats facing inwards. The self-driving revolution was imminent, they said. Well, it wasn't... but now it actually is! Humans have a hard time with scenarios like this. If you promise them the moon in eight months, but don't end up delivering until eight years later, most will justifiably be skeptical that it's actually here — even in the face of gushing anecdotes and video evidence. That's the problem with delayed promises. So when Jason told me Tesla's self-driving tech was finally ready and real, I was indeed skeptical. I tried FSD as late as last year, and I didn't enjoy it much. Impressive in many ways, but too jerky. Too many interventions. How much could it really have improved in nine months or so? A lot, it turns out. We started the drive from Jason's house, and I watched him not once touch the pedals or steering wheel while we drove half an hour to the other end of town. Then repeated the feat on the way back. But that wasn't even the most impressive part. What really blew my mind was how dramatically better the fluidity of driving with FSD has become. His new Model Y anticipated the red light with the manners of a drives-for-the-queen-level chauffeur. And the way it knew exactly how to slow down to prevent a jerky movement when taking an incline into an elevated parking lot? Sublime. Elon, that son of a bitch, seems to have done it again! Proven everyone wrong. Proven me wrong. The self-driving dream has flipped from vaporware to credible near-term reality. All without LiDAR. AI really delivering on this one.
Large web pages, especially documentation, benefit from having a table of contents for navigating within document. This article describes how I implemented a compact table of contents for documentation page for my Edna note taking application as well as for this very blog. I was inspired by Notion. It seems that others, like Substack, also were inspired by them. Here’s the compact version: Here’s full version shown when you hover mouse over compact version: Took only few hours and you can see the full code at https://gist.github.com/kjk/d9343c3f45d9f529b2b8156048254840 A good table of contents A good table of contents is: always available unobtrusive Full table of contents cannot be always visible. Space is at premium and should be used for the main text of the content. A compact for of table of contents should always be visible. I noticed that Notion implemented such an idea in a nice way. Since great artists steal, I decided to implement similar behavior for Edna’s documentation In compact view toc is just a column of small, gray rectangles. Each rectangle represents a toc entry. If rectangle is black, it represent currently visible entry. That gives user an indication where he is withing the document when scrolling. It’s small and unobtrusive, positioned either to the left or right. It can be anchored to the top or centered vertically. When you hover mouse over that area we show the actual toc: Clicking on a title goes to that part of the page. Implementing table of contents My implementation can be added to any page. Grabbing toc elements I assume h1 to h6 elements mark table of contents entries. I use their text as text of the entry. After page loads I build the HTML for the toc. I grab all headers elements: function getAllHeaders() { return Array.from(document.querySelectorAll("h1, h2, h3, h4, h5, h6")); } Each toc entry is represented by: class TocItem { text = ""; hLevel = 0; nesting = 0; element; } We show text to the user. hLevel is 1 … 6 for h1 … h6. nesting is like hLevel but sanitized. We use it to indent text in toc, to visualize the tree structure. element is the actual HTML element. We remember it so that we can scroll to that element with JavaScript. I create array of TocItem for each header element on the page: function buildTocItems() { let allHdrs = getAllHeaders(); let res = []; for (let el of allHdrs) { /** @type {string} */ let text = el.innerText.trim(); text = removeHash(text); text = text.trim(); let hLevel = parseInt(el.tagName[1]); let h = new TocItem(); h.text = text; h.hLevel = hLevel; h.nesting = 0; h.element = el; res.push(h); } return res; } function removeHash(str) { return str.replace(/#$/, ""); } Generate toc HTML Toc wrapper Here’s the high-level structure: .toc-wrapper has 2 children: .toc-mini, always visible, shows overview of the toc .toc-list hidden by default, shown on hover over .toc-wrapper Wrapper is always shown on the right upper corner using fixed position: .toc-wrapper { position: fixed; top: 1rem; right: 1rem; z-index: 50; } You can adjust top and right for your needs. When toc is too long to fully shown on screen, we must make it scrollable. But also default scrollbars in Chrome are large so we make them smaller and less intrusive: .toc-wrapper { position: fixed; top: 1rem; right: 1rem; z-index: 50; } When user hovers over .toc-wrapper, we switch display from .toc-mini to .toc-list: .toc-wrapper:hover > .toc-mini { display: none; } .toc-wrapper:hover > .toc-list { display: flex; } Generate mini toc We want to generate the following HTML: <div class="toc-mini"> <div class="toc-item-mini toc-light">▃</div> ... repeat for every TocItem </div> ▃ is a Unicode characters that is a filled rectangle of the bottom 30% of the character. We use a very small font because we want it to be compact. .toc-light is gray color. By removing this class we make it default black which marks current position in the document. .toc-mini { display: flex; flex-direction: column; font-size: 6pt; cursor: pointer; } .toc-light { color: lightgray; } Generating HTML in vanilla JavaScript is not great, but it works for small things: function genTocMini(items) { let tmp = ""; let t = `<div class="toc-item-mini toc-light">▃</div>`; for (let i = 0; i < items.length; i++) { tmp += t; } return `<div class="toc-mini">` + tmp + `</div>`; } items is an array of TocItem we get from buildTocItems(). We mark the items with toc-item-mini class so that we can query them all easily. Generate toc list Table of contents list is only slightly more complicated: <div class="toc-list"> <div title="{title}" class="toc-item toc-trunc {ind}" onclick=tocGoTo({n})>{text}</div> ... repeat for every TocItem </div> {ind} is name of the indent class, like: .toc-ind-1 { padding-left: 4px; } tocGoTo(n) is a function that scroll the page to show n-th TocItem.element at the top. function genTocList(items) { let tmp = ""; let t = `<div title="{title}" class="toc-item toc-trunc {ind}" onclick=tocGoTo({n})>{text}</div>`; let n = 0; for (let h of items) { let s = t; s = s.replace("{n}", n); let ind = "toc-ind-" + h.nesting; s = s.replace("{ind}", ind); s = s.replace("{text}", h.text); s = s.replace("{title}", h.text); tmp += s; n++; } return `<div class="toc-list">` + tmp + `</div>`; } Putting it all together Here’s the code that runs at page load, generates HTML and appends it to the page: function genToc() { tocItems = buildTocItems(); fixNesting(tocItems); const container = document.createElement("div"); container.className = "toc-wrapper"; let s = genTocMini(tocItems); let s2 = genTocList(tocItems); container.innerHTML = s + s2; document.body.appendChild(container); } Navigating Showing / hiding toc list is done in CSS. When user clicks toc item, we need to show it at the top of page: let tocItems = []; function tocGoTo(n) { let el = tocItems[n].element; let y = el.getBoundingClientRect().top + window.scrollY; let offY = 12; y -= offY; window.scrollTo({ top: y, }); } We remembered HTML element in TocItem.element so all we need to is to scroll to it to show it at the top of page. You can adjust offY e.g. if you show a navigation bar at the top that overlays the content, you want to make offY at least the height of navigation bar. Updating toc mini to reflect current position When user scrolls the page we want to reflect that in toc mini by changing the color of corresponding rectangle from gray to black. On scroll event we calculate which visible TocItem.element is closest to the top of window. function updateClosestToc() { let closestIdx = -1; let closestDistance = Infinity; for (let i = 0; i < tocItems.length; i++) { let tocItem = tocItems[i]; const rect = tocItem.element.getBoundingClientRect(); const distanceFromTop = Math.abs(rect.top); if ( distanceFromTop < closestDistance && rect.bottom > 0 && rect.top < window.innerHeight ) { closestDistance = distanceFromTop; closestIdx = i; } } if (closestIdx >= 0) { console.log("Closest element:", closestIdx); let els = document.querySelectorAll(".toc-item-mini"); let cls = "toc-light"; for (let i = 0; i < els.length; i++) { let el = els[i]; if (i == closestIdx) { el.classList.remove(cls); } else { el.classList.add(cls); } } } } window.addEventListener("scroll", updateClosestToc); All together now After page loads I run: genToc(); updateClosestToc(); Which I achieve by including this in HTML: <script src="/help.js" defer></script> </body> Possible improvements Software is never finished. Software can always be improved. I have 2 ideas for further improvements. Always visible when enough space Most of the time my browser window uses half of 13 to 15 inch screen. I’m aggravated when websites don’t work well at that size. At that size there’s not enough space to always show toc. But if the user chooses a wider browser window, it makes sense to use available space and always show table of contents. Keyboard navigation It would be nice to navigate table of contents with keyboard, in addition to mouse. For example: t would show table of contents Esc would dismiss it up / down arrows would navigate toc tree Enter would navigate to selected part and dismiss toc
My latest love letter to Linux has been published. It's called Omarchy, and it's an opinionated setup of the Arch Linux distribution and the Hyprland tiling window manager. With everything configured out-of-the-box to give you exactly the same setup that I now run every day. My Platonic ideal of what a developer environment should look like. It's not for everyone, though. Arch has a reputation for being difficult, but while I think that's vastly overstated, I still think it's fair to say that Ubuntu is an easier landing for someone new to Linux. And that's why this exists as a sister project to Omakub — my opinionated setup for Ubuntu — and not a replacement of it. Because I do think that Hyprland deserves its reputation of being difficult! Not because the core tiling window manager is hard, but because it comes incredibly bare-boned in the box. You have to figure out everything yourself. Even how to get a lock screen or idle timing or a menu bar or bluetooth setting or... you get the idea. Omarchy is an attempt to solve for all that. To give you a default set of great, beautiful configurations for Hyprland, and installing all the common tooling you'd normally want. You could setup this, not change a thing, and you'll have exactly what I run every day. But you can also just use this as a paved path into the glorious world of Linux ricing. The flip side of Hyprland being so atomized is that it's infinitely configurable. You can really, really make it yours. No wonder its the preferred platform for r/unixporn, and even what PewDiePie picked up for his amazing Russian nuclear core build. I don't know when we'll literally get "The Year of Linux on the Desktop", but I've never been as convinced that its coming as I am now. There's enough dissent in the water. Enough dissatisfaction with both Apple and Microsoft. And between Valve going all-in on Steam on Linux (the Steamdeck runs Arch!), major creators (like PewDiePie) switching to Linux, and incredible projects like Hyprland — which offer not just a cheap visual copy of the two major commercial operating systems, but something much more unique and compelling — I think all the factors are in place for a big switch. At least among developers. But broad adoption or not, I'm in love with Linux, and thrilled to share my work to make it easier to enjoy.
Here’s a story from nearly 10 years ago. the bug I think it was my friend Richard Kettlewell who told me about a bug he encountered with Let’s Encrypt in its early days in autumn 2015: it was failing to validate mail domains correctly. the context At the time I had previously been responsible for Cambridge University’s email anti-spam system for about 10 years, and in 2014 I had been given responsibility for Cambridge University’s DNS. So I knew how Let’s Encrypt should validate mail domains. Let’s Encrypt was about one year old. Unusually, the code that runs their operations, Boulder, is free software and open to external contributors. Boulder is written in Golang, and I had not previously written any code in Golang. But its reputation is to be easy to get to grips with. So, in principle, the bug was straightforward for me to fix. How difficult would it be as a Golang newbie? And what would Let’s Encrypt’s contribution process be like? the hack I cloned the Boulder repository and had a look around the code. As is pretty typical, there are a couple of stages to fixing a bug in an unfamiliar codebase: work out where the problem is try to understand if the obvious fix could be better In this case, I remember discovering a relatively substantial TODO item that intersected with the bug. I can’t remember the details, but I think there were wider issues with DNS lookups in Boulder. I decided it made sense to fix the immediate problem without getting involved in things that would require discussion with Let’s Encrypt staff. I faffed around with the code and pushed something that looked like it might work. A fun thing about this hack is that I never got a working Boulder test setup on my workstation (or even Golang, I think!) – I just relied on the Let’s Encrypt cloud test setup. The feedback time was very slow, but it was tolerable for a simple one-off change. the fix My pull request was small, +48-14. After a couple of rounds of review and within a few days, it was merged and put into production! A pleasing result. the upshot I thought Golang (at least as it was used in the Boulder codebase) was as easy to get to grips with as promised. I did not touch it again until several years later, because there was no need to, but it seemed fine. I was very impressed by the Let’s Encrypt continuous integration and automated testing setup, and by their low-friction workflow for external contributors. One of my fastest drive-by patches to get into worldwide production. My fix was always going to be temporary, and all trace of it was overwritten years ago. It’s good when “temporary” turns out to be true! the point I was reminded of this story in the pub this evening, and I thought it was worth writing down. It demonstrated to me that Let’s Encrypt really were doing all the good stuff they said they were doing. So thank you to Let’s Encrypt for providing an exemplary service and for giving me a happy little anecdote.
Go is the most hated programming language. Compared to other languages, it provides 80% of utility with 20% of complexity. The hate comes from people who want 81% of utility, or 85% or 97%. As Rob Pike said, no one denies that 87% of utility provides more utility than 80%. The problem is that additional 7% of utility requires 36% more work. Here are some example. Someone complained on HN that struct tags are a not as powerful as annotations or macros. I explained that this is 80⁄20 design. Go testing standard library is a couple hundred lines of code, didn’t change much over the years and yet it provides all the basic testing features you might need. It doesn’t provide all the convenience features you might think of. That’s what Java’s jUnit library does, at a cost of tens of thousands lines of code and years of never-ending development. Go is 80⁄20 design. Goroutines are 80⁄20 design for concurrency compared to async in C# or Rust. Not as many features and knobs but only a fraction of complexity (for users and implementors). When Go launched it didn’t have user defined generics but the built-in types that needed it were generic: arrays/slices, maps, channels. That 8⁄20 design served Go well for over a decade. Most languages can’t resist driving towards 100% design at 400% the cost. C#, Swift, Rust - they all seem on a never-ending treadmill of adding features. Even JavaScript, which started as a 70⁄30 language has been captured by people whose job became adding more features to JavaScript. If 80⁄20 is good, wouldn’t 70⁄30 be even better? No, it wouldn’t. Go has shown that you can have a popular language without enums. I don’t think you could have a popular language without structs. There’s a line below which the language is just not useful enough. Finally, what does “work” mean? There’s work done by the users of the language. Every additional feature of the language requires the programmer to learn about it. It’s more work than it seems. If you make functions as first class concepts, the work is not just learning the syntax and functionality. You need to learn new patterns coding, like functions that return functions. You need to learn about currying, passing functions as arguments. You need to learn not only how but when: when you should use that powerful functionality and when you shouldn’t. You can’t skip that complexity. Even if you decide to not learn how to use functions as first class concepts, your co-worker might and you have to be able to understand his code. Or the library you uses it or a tutorial talks about it. That’s why 80+% languages need coding guidelines. Google has one for C++ because hundreds of programmers couldn’t effectively work on shared C++ codebase if there was no restriction on what features any individual programmer could use. Google’s C++ style guide exists to lower C++ from 95% language to 90% language. The other work is by implementors of the language. Swift is a cautionary tale here. Despite over 10 years of development by very smart people with practically unlimited budget, on a project that is a priority for Apple, Swift compiler is still slow, crashy and is not meaningfully cross platform. They designed a language that they cannot implement properly. In contrast Go, a much simpler but still very capable, was fast, cross platform and robust from version 1.0.