
Programming
Rust from a Scala Perspective: Advent of Code 2024


Jordan Van Forest
2/10/2025
I try to use AoC as an opportunity to try new languages. After last year’s encounter with Kotlin, I decided to tackle Rust.
My goal? To determine whether Rust is a good language (spoiler: yes, it is), whether it’s suitable for general backend development (no, it isn’t) and whether I’d like to write it every day (no, I absolutely wouldn’t).
On a side note: I’m publishing this a long while after completing AoC because I couldn’t really convince myself that I have anything to say that wasn’t said already. But maybe I do?
I start with a bit of the usual language comparison, but it’s just a pretext for more abstract divagations on different problems in software development.
What I Liked
include_str!macro – Great and predictable way to use an externally defined string. Much less of a footgun than JVM resources.No explicit
returnneeded – Rust's expression-based syntax allows returning values without areturnstatement, which felt natural and concise.Parallel iteration with Rayon (
par_iter()) – It was straightforward to introduce parallelism with Rayon. I like having such things in stdlib, but adding a crate wasn’t a big deal.Forward-looking type inference — Unlike Scala, Rust sometimes infers types based on later usage, which was intriguing to say at least. (Yeah, I know this thing probably has a proper name)
Immutable collections (
impackage) – Rust has third-party support for immutable collections, though it’s not a built-in.Easy enum support (and other derivations)— No built-in iteration over enum values (similar to Scala), but deriving it was effortless.
Borrowing was not too hard — It was a completely new concept to me, but grasping it (on a basic level) was not overly difficult.
Tooling mostly works — had very little issues with it, maybe despite the debugger (more on it below).
What I Didn’t Like
There are just a few things that were not great and important. And quite a few not-so-important ones.
Important
Debugger is crap — Okay, it’s probably an improvement over C or C++, but for anyone coming from JVM world it will feel like a massive downgrade. Not everything can be inspected, visualizations are poor, there is no dynamic expression evaluation. (I’m speaking about what’s available in IntelliJ/RustRover)
Weird mix of imperative and functional concepts — Developing in Rust felt like “let’s do FP until you can’t and switch to imperative then”. This was not a comfortable experience. I like languages with a clearer approach and more firmly standing on one side of the fence.
AI strongly favours mutable solutions — More on AI later, but for me this is a sign of a general language and ecosystem mindset. Even if I gave a strictly functional signature, e.g. designed for a recursive implementation, it followed with an imperative one. It’s very important in the spirit of “it doesn’t matter what is possible, it matters what happens”. If most of the code in a given language is imperative, it doesn’t matter that it has functional concepts baked in, it’s not a functional language.
Borrow-checker makes things complicated — Or close to impossible. While it’s ok most of the time, I’ve hit at least one issue where it prohibited a perfectly safe and valid use case.
Nitpicking
;and{}in pattern matching – Seriously? It felt like writing C again.String vs.
str– The distinction betweenStringand&strwas annoying. I couldn’t really convince myself to try to understand why it exists (there is a reason probably), but it doesn't change the fact that it was slowing me down.Nested functions can’t capture variables — There is probably an explanation for that, but it still kills half of the benefits of using nested functions.
No short lambda syntax – Rust doesn’t seem to have the equivalent of Scala’s
_.foowhich makes code much more verboseGraph algorithms — I couldn’t find a crate that would allow finding a clique on Day 23. Maybe it’s my poor research skills, but for now I will interpret it as a sign of a not-so-mature ecosystem (which is understandable, considering language age).
False positive “never used” — The compiler mistakenly flagged a function as unused if it was only reachable indirectly. Not a big deal but annoying and basic.
Pointers still exist — The last time I had to use them was at uni, more than a decade ago. While I understand the need for them, I don’t appreciate the experience.
snake_case — C’mon, everyone should know that camelCase is the only sane way to name variables. Don’t even try to discuss that.
Can’t run an arbitrary file — On the JVM I can just implement
mainin a random file and run it. Not the case in Rust, it requires a much stricter approach.
While the list might look long (and longer than the list of positives), I did like the language as a whole. It's well-designed and powerful. That being said…
Why Rust is Not Good (For Me)
There are certain problems I care about and enjoy dealing with on a daily basis. Those problems include:
Maximizing single developer productivity
Expressing complicated domains and business requirements as cleanly and as conveniently as possible
Building large-scale systems in multi-people environments
That’s why my language of choice is Scala, which might not solve those problems but at least opens a very interesting solution space.
Rust, on the other hand, aims to solve a very specific set of problems, including:
Memory safety without garbage collection
Concurrency without data races
High performance with zero-cost abstractions
Those are important problems to solve, but I, personally, couldn’t care less about them. I do want performance and memory safety, I just don't want to actively think about it for more than absolutely necessary. And unfortunately, Rust forces you to think about them all the time.
Going further, I also believe my preferred problems are much closer to general backend development and product development. This might be challenged, but until convinced otherwise, I will rely on this belief. And through the lens of that, I believe Rust is a terrible choice for general backend product development. And not because it’s a bad language (because it isn’t) but because it focuses on wrong problems for that particular domain.
Summary
Rust is a really good system programming language. If I were building high-performance systems, embedded applications, or low-level networking code, Rust would be a great choice. But for the kind of backend development I typically do in Scala? It’s not worth the trade-offs.
Bonus: How Good or Useful is AI These Days?
My everyday exposure to AI-assisted coding is quite limited because I very rarely deal with clear problems. I usually have no idea what is my aim, and AI is not yet able to help me figure that out. Hence AoC gave me a refreshing perspective of solving clearly defined problems. Below are some observations of mine from this opportunity:
Overcomplicates things — Or is limited. On Day 13 it proposed a rather complicated numeric algorithm when a rather simple analytic solution would yield much better results.
Still makes mistakes — Reviewing diffs carefully is essential, as AI can introduce subtle (or major) errors. Among three dozen problems, it solved maybe five correctly on the first try. Which is still amazing but far from perfect.
Can significantly help in complex problems — On Day 19, AI provided a dynamic programming solution that I probably wouldn’t have figured out myself.
Polishing solutions with AI — Using AI to refine solutions was a big help (I could just scratch some very ugly code and get it refined automatically), but it required constant vigilance and often introduced subtle bugs.