![]() |
VOOZH | about |
We’re so glad you’re here. You can expect all the best TNS content to arrive Monday through Friday to keep you on top of the news and at the top of your game.
Check your inbox for a confirmation email where you can adjust your preferences and even join additional groups.
Follow TNS on your favorite social media networks.
Become a TNS follower on LinkedIn.
Check out the latest featured and trending stories while you wait for your first TNS newsletter.
As we’ve discussed numerous times over the years, developers have been anticipating the addition of generics to Go for a long time now. The feature has been the most highly requested for more than a decade now and it finally arrived just last month to much celebration with the release of Go 1.18.
Since the release of the long-awaited feature, there have been tutorials, demos, and discussions aplenty, but this week the discussion has taken a bit of a turn, questioning whether the feature is really ready for prime time.
In a blog post on his company’s blog, Vicent Martí, who works on performance for MySQL-compatible serverless database platform PlanetScale, writes that generics can make your Go code slower.
I don’t think Generics in Go 1.18 are ready for widespread adoption. Their performance is concerning. My review on the @planetscaledata blog: https://t.co/mJVIj9MQ5u
— Vicent Martí (@vmg) March 30, 2022
In his blog post, Martí says that, while there has been some opposition to generics for fear that the language will become “a verbose and Enterprisey Java-lite with Generic Factories or, most terrifyingly, a degenerate HaskellScript that replaces ifs with Monads,” others simply hope that generics will provide “a critical feature to implement clean and reusable code at scale.” Outside of this dynamic, however, exists a third party, to which he belongs: “systems engineers who are not excited about generics per se, but about monomorphization and its performance implications.”
There are generally two ways to implement generics, writes Martí. First, you can use “boxing”, wherein pointers help to abstract and make all “things” (his preferred non-technical term for this discussion) that a function will operate on “look and act the same way”. This is the approach used for Go interfaces, dyn Traits in Rust, and virtual classes in C++, but he says that they “are limited by their expressiveness and by their runtime overhead.” Second, you can use monomorphism, which essentially creates “a different copy of the function for every unique thing it must operate on” and has historically been the choice for implementing generics in various languages, as it “boils down to trading longer compile times for significant performance gains in the resulting code.”
Didn’t we talk about this at Gophercon?
Some discussion on this issue: https://t.co/sNftruzAV9— Bryan Boreham 💉💉💉 (@bboreham) March 30, 2022
The downside of monomorphization, however, is that it creates a lot more code, and so Go took a bit of an in-between path, with an approach it calls “GCShape stenciling with Dictionaries.” Rick Branson, director of software engineering at PlanetScale, offered a bit of a summary of this point in an email.
“There are some very real cases where generating specific code for every type permutation of generic code will dramatically increase compile times and the resulting compiled executable size to the point where it is problematic. It can even result in slower code execution in some cases! So the Go compiler doesn’t actually generate new code for every single type permutation. It uses a number of heuristics, including ‘GC Shape Stenciling’ which makes trade-offs to keep the number of permutations reasonable. In some cases, these trade-offs reduce performance in an unfavorable way because the generated machine code can’t be that lean, mean, special purpose code. It must support a broader range of types when executed. This is a lot of what the blog post discusses,” Branson wrote.
Martí spends much of the blog post taking a very technical, and beautifully formatted, deep dive into the details of what makes this so, which we will let this summary stand in for, but if you’re dying for more specifics, they are there in spades. Moving past that, however, what we arrive at is a more succinct list of dos and don’ts for how to get the best of generics performance as it is currently designed, and Martí’s suggestions on how Go might amend its design to further increase runtime performance.
Martí summarized his opinion on the matter in an email, writing that he believes that “the right trade-off for a systems language (and any compiled language, really) is paying the upfront cost when compiling to generate a zero-cost generics abstraction at runtime. That’s the baseline, and the only sensible approach in my opinion: first, you make the compiler generate the best possible code in every circumstance. Then, you benchmark the compiler, and if it’s too slow, you work on optimizing the compiler. Incidentally, if the compiler for your language is written in your language (like it’s the case for Go), making it generate better code _also_ speeds up the compiler itself!”
The next major version of React, React 18, just launched. There’s some *really* cool stuff in this one, and it sets the stage for even more stuff in the future! 😮
Gonna share some of the things I’m most excited about in-thread. 🧵
— Josh W. Comeau (@JoshWComeau) March 30, 2022
have just learned python is pronounced like “pee-thon” in french and like “poo-thon” in finnish and i’m not sure i’ll ever recover because i am a child
— social media remains a bad idea 🇺🇦 (@techpractical) March 29, 2022