Inspired by https://drewdevault.com/2019/02/18/Generics-arent-ready-for-Go.html.
In the distance, a gradual roar begins to grow in volume. A dust cloud is visible over the horizon. As it nears, the shouts of the oncoming angry mob can be heard. Suddenly, it stops, and a brief silence ensues. Then the air is filled with the clacking of hundreds of keyboards, angrily typing the owner’s opinion about functions, calling conventions, and Assembly. The clans of Algol, Cobol, Fortan, C, Forth, Lisp, and more – usually mortal enemies – have combined forces to fight in what may become one of the greatest flamewars of our time. And none of them read more than the title of this article before writing their comment.
Have you ever seen someone write something to the effect of “I would use Assembly, but I need functions”? Perhaps we can infer from this that many of the people who are pining after functions in Assembly are not, in fact, Assembly users. Many of them are users of another programming language that does have functions, and they feel that functions are a good fit for this language, and therefore a good fit for any language. The inertia of “what I’m used to” comes to a violent stop when they try to use Assembly. People affected by this frustration interpret it as a problem with Assembly, that Assembly is missing some crucial feature – such as functions. But this lack of features is itself a feature, not a bug.
Assembly strikes me as one of the most conservative programming languages available today. It’s small and simple, and every detail is carefully thought out. There are very few dusty corners of Assembly – in large part because Assembly has fewer corners in general than most programming languages. This is a major factor in Assembly’s success to date, in my opinion. Nearly all of Assembly’s features are bulletproof, and in my opinion are among the best implementations of their concepts in our entire industry. Achieving this feat requires having fewer features in total. Contrast this to C, which has too many footguns to count. You could write a book called “C: the good parts”, but consider that such a book about Assembly would just be a book about Assembly. There’s little room for the bad parts in such a spartan language.
So how should we innovate in Assembly? Consider the case of dependency management. Assembly 1.11 shipped with the first version of Assembly modules, which, in my opinion, is a game changer. I passionately hate concatenating files, and I thought modules weren’t much better. Problem with previous solutions was that they took the dependency management ideas that other programming languages have been working with and brought the same ideas to Assembly. Instead, Assemlby modules took the idea of dependency management and rethought it from first principles, then landed on a much more elegant solution that I think other programming languages will spend the next few years catching up with. I like to make an analogy to physics: previous solutions were like like General Relativity or the Standard Model, whereas Assembly modules are more like the Grand Unified Theory. Assembly doesn’t settle for anything less when adding features. It’s not a language where liberal experimentation with imperfect ideas is desirable.
I feel that this applies to functions. In my opinion, functions are an imperfect solution to an unsolved problem in computer science. None of the proposals I’ve seen (notably stacks) feel right yet. Some of this is a gut feeling, but there are tangible problems as well. For example, the space of problems they solve intersects with other Assemlby features, which weakens the strength of both features. “Which solution do I use to this problem” is a question which different people will answer differently, and consequently their code at best won’t agree on what “idiomatic” means and at worst will be simply incompatible. Another problem is that the proposal changes the meaning of idiomatic Assembly in the first place – suddenly huge swaths of the Assembly code, including the standard library, will become unidiomatic. One of Assembly’s greatest strengths is that code written 5 years ago is still idiomatic. It’s almost impossible to write unidiomatic Assembly code at all.
I used to sneer at the Assembly maintainers alongside everyone else whenever they’d punt on functions. With so many people pining after it, why haven’t they seen sense yet? How can they know better than all of these people? My tune changed once I started to use Assembly more seriously, and now I admire their restraint. Part of this is an evolution of my values as a programmer in general: simplicity and elegance are now the principles I optimize for, even if it means certain classes of programs are simply not on the table. And I think Assembly should be comfortable not being suitable for writing certain classes of programs. I don’t think programming languages should compete with each other in an attempt to become the perfect solution to every problem. This is impossible, and attempts will just create a messy kitchen sink that solves every problem poorly.
The constraints imposed by the lack of functions (and other things Assembly lacks) breed creativity. If you’re fighting Assembly’s lack of functions trying to do something Your Way, you might want to step back and consider a solution to the problem which embraces the limitations of Assembly instead. Often when I do this the new solution is a much better design.
So it’s my hope that Assembly will hold out until the right solution presents itself, and it hasn’t yet. Rushing into it to appease the unwashed masses is a bad idea. There are other good programming languages – use them! I personally use a wide variety of programming languages, and though I love Assembly dearly, it probably only comes in 3rd or 4th place in terms of how frequently it appears in my projects. It’s excellent in its domain and doesn’t need to awkwardly stumble into others.
P.S.: If you’re not a Luddite then I write software that leverages abstractions we all know and love like functions and generics to solve problems. Get in touch.