My New Favorite Language: Elixir
I want to talk about functional programming and Elixir, which is easily my new favorite programming language. It's not even close. I freaking love this thing. This is some of the Elixir code that I wrote for Advent of code. I wanted to learn a new language for Advent of code and I ended up choosing Elixir. I didn't do every single day, I did like 12 of them, but these were very much dedicated to learning, not necessarily like competing or doing anything like that. And it was a really good way of getting acquainted with the language, and what a language it is indeed.
I don't really know what the best way to structure this video is, so I think what I'm going to do is just run through this code base and just gush about all the things I think are really sick about functional programming and Elixir. And the first one is right here.
The Elegance of the Pipe Operator
The pipe operator. This function right here, the whole point of it is to take in some input, which for this project was all of this, take that in, parse it, turn it into a format that we can use to actually solve the problem. And the code for this is great because we start with String.split, which is a function because everything's a function. Even what you pass into an if statement is a function.
So we do our String.split, we pass the result of String.split into Enum.map as the first parameter of the function. So we do Enum.map over the result of that because we're grabbing all the different blocks of text. We're looping through all the lines in each of the blocks, we're splitting those up into characters, and then we get this multi-dimensional array of grids which we can then use to solve the problem. It's amazing.
Immutability and New Iteration Patterns
The other thing that's really weird about Elixir and these functional programming languages is the fact that basically everything has to be done with either recursion or these kind of helper functions that the Enum package provides or other packages like it. Right here we're doing Enum.map which is very similar to a map function in JavaScript or something like that. And we have stuff like Enum.reduce, Enum.map obviously, and all these different things to iterate over a collection, but a traditional for loop or while loop like you're used to in JavaScript or Python or whatever the hell doesn't really exist here.
And it screwed with my brain for the first couple days trying to figure out exactly how these programs are supposed to work and feel. Because another thing is we don't really have variables, at least in the sense that you would think. Everything is a constant because mutability doesn't exist. You cannot mutate a variable, you can only reassign it or something like that. So right here when we do this character entry is Enum.at(block, line) and then Enum.at(call) which would be kind of like array[1][2] or something in language that you're probably more familiar with. But this character entry right here cannot be reassigned. And in this case it didn't really matter because we were just using that to check whether or not it was a hashtag. And then we go through in here and do some recursion, because this language is full of recursion, which I personally really like.
A Simple Explanation of Recursion
If you already get recursion, skip like two minutes ahead in this video. But for those who don't, I really, really like this example. It's how it clicked for me the first time. And the example is the power function. So we imagine 2 to the 4 is what this is. So power(2, 4) is 2 to the 4th, but we can rewrite 2 to the 4th as 2 * 2 * 2 * 2, which we can then rewrite as 2 to the 3rd * 2. And you can probably already see where this is going, because what this really is saying is this is saying 2, which is this, times 2 to the 3rd, which is power(2, 3). And then what we can do down here is we can say power(2, 3) * 2 is equal to power(2, 4).
And this is basically how the recursion works. It's basically just taking our function and making it smaller, if that makes any sense, and just going down the chain and doing it. And the actual code for this would be power(n, p) and then we're just doing return power(n, p-1) * n like we showed above. But then we have this other thing right here where we're saying if p equals 0, return 1. And this is the base case, which is effectively where we want to stop doing recursive calls. And a recursive call is just calling the function inside of itself. So the base case for power is just going to be when p equals zero, because anything to the zero is one. So we can just say if p equals 0, return 1. And when we return that one, that means that our last entry of power here, so if we had power(2, 0) * 2, that would be our final case here, which would then result in 1 * 2. And then all of those get returned back up the chain and we end up with the correct answer.
The Functional Mindset for Web Development
And in Elixir, you have to do a lot of this. I did so much recursion in this. This was honestly one of the more chill problems I did. I did a lot of like DFS in this. It was a very heavy grid year in Advent of Code for some reason. Like I feel like I wrote this function 12 times where we were just taking some input, turning it into a grid, and then working with that grid.
But yeah, it was really cool having to think about programs through recursion, having to think about things without mutability is just such a good way of thinking about it. Because really, the way this has forced me to think about programs in writing these things is just as transformations of data and eliminating basically all forms of state except for like one. And this works really well in the web development world if you think about things from a serverless perspective, where our one source of truth is usually going to be our database or KV store or whatever the hell it is. And everything we're defining, all of our endpoints, all of the buttons on the front end, all of the backend queues or whatever, the state for these is not something that's shared between them. It is literally just when you go to like GET /users or whatever, there's no state inside that function except for the database. So it is just a function. And that kind of functional programming mindset makes so much sense there and I just really, really like it. I have had so much fun working with this.
The Real-World Challenges of Elixir
I highly recommend it, even if I think Elixir is not the most practical language right now, unfortunately. I have another video that I'm making about this where I talk about the AI stuff I've been working with lately and how wrong I was about how useful it is. It's really, really, really good. But Elixir for building like web applications and stuff like that, you basically have to use the Phoenix framework, and there are a lot of issues with that, to be honest. There are a lot of things that are kind of annoying that I don't like. I'm going to keep building with it, but I definitely will have a dedicated like feedback video on like, 'Hey, here's what's wrong with the Phoenix framework and why I wouldn't adopt it over just full stack JS world type stuff.' 'Cause I do think that is kind of eating the world. It feels hard to justify not using that everywhere just because it works so well with all the providers, it works amazing on AWS, it is so well supported. There is so much stuff there.
You know, working with Elixir, it feels like a different world because everything is just so much smaller and more niche and clearly less supported. The LLMs do not work nearly as well because there's way less data on it. A lot of the packages are very small and kind of half-maintained, and the documentation feels kind of weird. Like I spent like three hours in the airport the other day trying to get environment variables set up the way I wanted them to be, like with a .env in TypeScript, which takes two seconds to set up. In Elixir, I just fought it and fought it and fought it, and eventually I just gave up and just set my .env file to have export right before all the environment variables. So I run source .env right before I start my server, and it works. Again, is that the biggest thing in the world? No, but the fact that it was that difficult to do something like that is rough.
Functional vs. OOP & Final Thoughts
100%, but outside of that stuff, the actual language itself and when you're working with it in a program like this is incredible. I cannot recommend it enough. I think it is making me a better programmer having to think about problems in this way. It's just better than the OOP stuff I've had to do forever because my college experience was all object-oriented programming. My core software class was a Java class effectively. What the entire class was was just going through and taking all of these utility functions—a map, a set, a queue, a natural number, whatever—and then going through and implementing those via object-oriented programming. We would write the tests, we would write the interfaces, we would write the abstract classes, and then we would write five different implementations using five different things to kind of show off how all this works. And it was cool, but in the real world and the stuff that I'm actually building now, I have just no interest in building that way, and I am much happier with this functional programming. And I really wish that this was taught in university, but again, that's another video for another day. I think that the modern CSE college experience is an important video that I really should make 'cause I was just there.
But yeah, I know I went everywhere with this one. I had a lot of trouble figuring out how I wanted to do this video, but I hope you get the picture. Immutability, recursion, functional programming, Elixir—it's all amazing. I highly recommend checking it out, and I'll have more to say about this in the future. If you enjoyed, make sure you like and subscribe, and I'll talk to you later.