For a long time while my day jobs were centered in Python, C and C++, I was separately very interested in strict functional programming, particularly in Haskell and slightly less but somewhat in Scala. I taught myself enough to be roughly an “advanced intermediate” programmer in both languages just via tutorials and side projects.

In the time since, I’ve had a job working in a large Haskell codebase and a separate job in a large Scala codebase. I remember feeling a lot of pride and self-confidence when I passed difficult technical interviews hitting on pragmatic day-to-day issues in these languages despite having not had prior job experience with them.

After years of working in these languages, I’ve basically had a 180 degree flip in my opinion of them at least in terms of solving business problems.

I no longer have any desire to work in functional programming, and believe that many of the promises it makes in regards to type safety, encoding IO or side-effectful operations into the type system, automatic parallelism, fast compile times, etc., are mostly just fantasies achievable only in idealized settings, and that there are fundamental incongruencies between the types of mutable systems that customer-facing products represent and immutable design patterns that make the goals of software as a product development activity incompatible with functional programming.

Since my background is in mathematics, I had always loosely believed that programming languages are supposed to go in the direction of removing any mental burden placed on the programmer to know how to represent a concept inside the syntax of the language.

What I mean is, I had always thought for example that if a language requires me to know something about computer memory layouts or the data structure internals of say, floating point values, then it’s a failure of the language and it should instead present me with an abstraction that renders those memory details or data structure internals to be unnecessary in all possible situations.

In many ways I think functional programming and the idea of formal verification generally is a type of expression of this way of thinking.

But my 180 degree change of heart has made me feel based on my experiences that it’s really the opposite. In all situations, I will frequently need access to every layer of abstraction possibly all the way down to the actual chemistry or physics of hardware components, and at the very least I’ll need no abstractions wrapping memory layout or data structure internals.. I’ll always need to get outside of the abstraction and “do it myself” so to speak.

This has in turn led me back to C/C++, some assembly and direct llvm programming, and writing a lot of Python tools that expose more of these lower level concerns at the Python level.

In a sense, I feel now more like there are not really programming languages so much as there are specific pieces of software tightly coupled with specific pieces of hardware, and I may need to modify or subvert fixed rules or abstractions of any part of it. Then a programming language just ends up being whatever common pattern of stuff on the software side ends up being useful enough to get repeated from project to project, and I don’t think it’s an accident that C is such a ubiquitous language in this sense.