What Language am I using for Advent of Code 2023?

This year I'm learning a new language with advent of code

Share on:  
  

Advent of Code 2023

First, a Short Story

Pretend you’re me, a few months from now. You log into work at the startup that employs you, and you start working on yesterday’s ticket. By chance, you log into AWS console to test something. You notice something on your way to whatever service you needed to look at.

COSTS UP 3482% COMPARED TO LAST MONTH

uhhh…. what?

We should look at that.
We should look at that now.

click click click

Why has everything scaled so much? Our lambdas, our db cluster, everything? It’s … massive?

Surely this is a mistake.
You look at the most recent deployment. It fixes a typo in a translations file.
You look at the second-most recent deployment. It’s clean too.

So, DDoS then? But wait, no, we use Cloudflare, we shouldn’t get DDoS.

Finally, you check google analytics. Traffic is UP

You check your analytics. Sales are up, new memberships are WAY UP.

You check social media. Your biggest competitor went out of business, and everyone is flocking to you and your service!

You’ve done it! You’ve actually done it! You and your team have crossed the infamous adoption chasm and it happened overnight!

But your costs are still so high …

And now you have to deal with it. You abandon whatever feature you were working on and start profiling your product. You find 3 areas that are using WAY more compute and memory than they should. Dutifully, you start trying to optimize the first one.

1 Week Later…

Your growth is continuing much faster than you could ever hope to optimize this ruby code. The day you’ve hoped for and feared is upon you. Nothing else makes any sense to tackle this problem.

You have to re-write it.
Ruby just won’t cut it. Neither will JavaScript, Neither will python.
Java probably won’t either, too much memory usage there.
Go would work for the current traffic levels, but when will your growth stop?
No, you need as much performance as possible.

Rust or C++?

What do you have to reach for when you need to build something big and fast? Right now, I currently have nothing, which is what I want to fix with Advent of Code this year. In the situation I described above, really only 2 things make sense in my head. C++ or Rust. I wouldn’t want to fall back on my C knowledge from university. I would take far too long making strings.

So, which one did I choose? Let’s break it down.

Criteria

This decision, like any other, is going to be about tradeoffs. We can’t evaluate these tradeoffs without first defining criteria for what is good and what is bad.

So, what is ideal in a fast non-garbage-collected language?

  1. Fast (or else we wouldn’t be choosing this language)
  2. Feature-Complete (or else we couldn’t choose this language)
  3. Good Development Tooling
  4. Usable in Industry
  5. Prevents Errors

I’ll explain the list briefly.

Fast

Now normally, I’m not a speed demon, and most of what I do doesn’t need blazing performance. However, these languages aren’t for every use case. We’re not writing scripts with these languages, we’re making things that require performance. This is the category of languages that we need to be fast. If either Rust or C++ turns out to be not as fast as what we would expect, that would disqualify them from being chosen.

Feature-Complete

I have no desire to program in a language that cannot yet open files or work effectively with strings. Like speed, this is a disqualifying criterion. Any language without feature completeness is not one I will be using for advent of code.

Good Development Tooling

I also have no desire to program in a language without a good debugger, language server, IDE support, build system, package system, community-supported packages, and the like.

All of these make development fast. My hourly rate is very expensive, and I want to deliver all that I can for that hourly rate. I don’t want to spend hours printf debugging when I could have spent 10 minutes in a debugging session.

Likewise, every time I get a red squiggly line in my editor telling me there is an error, it saves me a compile to check. Good, updated packages served in a modern way are useful. Could you imagine writing a web backend from scratch in ruby without rails? Me neither.

Usable by Industry

While I like learning just for the sake of learning, I also need to buy groceries every month. For that reason, something that is used in industry is important to me. You know, industry. The thing that pays us. We should listen to what it wants at least some of the time (although we should tell it to move on from Java 8.) The more something is used in industry, the more likely it is that I will be paid for this skill.

Prevents Errors

I don’t like writing bugs. It costs the company money in debugging and remediation time, and it costs the company money in lost users. If the language can prevent me from doing something stupid, I’ll take it every day.

As a side note, this is why I’m a fan of explicit static types, TDD, and null safety. Any guarantee that my code doesn’t have bugs I will take.

For example, I think the very best feature of Kotlin is adding nullability to the types in a way that makes a language that is nearly null-safe. I’ve written too much java and fixed too many production NullPointerException’s to like the concept of null.

Rust Evaluation

First, let’s evaluate Rust by these criteria. I’m not going to be assigning hard numbers to these evaluations, after all this is just for advent of code. If this was an evaluation I was proposing in a technical report, the structure would be much more formal and the conclusions backed up with much more empirical evidence.

Rust’s Speed

Rust is a statically compiled language with no garbage collection. It is fast.

Looking at some benchmarks that I found online, Rust is comparable in speed to C (which is about as fast as code can go).

Full benchmarks can be found here: https://programming-language-benchmarks.vercel.app/c-vs-rust

In any case, Rust is fast enough to be in this race.

Rust’s Feature-Completeness

Rust is feature-complete. There isn’t anything that I need a programming language to do that Rust cannot.

Rust’s Development Tooling

Rust has some good development tooling. Rust can be easily installed with the instructions at https://rustup.rs/. It has a package repository, https://crates.io/, all managed by cargo, the package manager, build tool, and test tool, rolled into one. It all even comes with docs at https://docs.rs/

There is a language server, rust analyzer, a formatter, rustfmt, and … clippy?

Yes, they brought back clippy, and made him into a linter. Those mad lads at Rust have been busy, I guess.

From what I can see, many of the most popular Rust crates (packages) are actively maintained. This is very important for security reasons. Every unmaintained package that your project takes on as a dependency is a potential time bomb, and one that nobody else is going to defuse for you.

Now, not that it’s likely to matter for advent of code, since the programs are so small, but I’ve seen online that compilation time for Rust is quite long. If you’re looking to build bigger programs with it, this is probably something important to consider.

Also, I can’t see myself picking Rust for any embedded system right now, as the first tutorial I found for it seems to say that I need a nightly build of Rust and to clone some dude’s GitHub repo just to make an Arduino uno work.

The second tutorial I found targeted a different board and looks much more supported. However, I’m still not convinced that the amount of support needed for embedded systems design is there in Rust.

Rust’s Industry Adoption

Rust has been getting some spotlight in recent months and years for the adoption that it has been receiving in industry. It’s still miles and miles behind C++, but it’s in the Linux kernel, it’s in chrome, it’s in the windows kernel, it’s in the alacritty terminal (that I use at home), it’s in the warp terminal (that I use at work), it’s in AWS, Facebook, Cloudflare, and Discord.

Of course, many of those technologies are predominantly C++ or C, but I’m legitimately impressed at how many projects have at least tried a little bit of Rust. It was more than I was expecting.

While Rust doesn’t get full marks here, I’m impressed.

Rust’s Error Prevention

Rust appears to have some decent error prevention built into the language. It has memory safety as a design feature, and that is something rare in this space, since neither C++ nor C can technically offer that.

That’s very appealing to me. It’s one thing to say we should just be better programmers and not leak our memory or overrun buffers, but it’s another thing to admit that we are fallible as people, and design a language with policies that take that into account.

Rust also has null safety in the form of the Option type, instead of nullable types. I like that a lot too.

I take cybersecurity very seriously, and memory safety issues make up a massive number of the vulnerabilities listed each year. Don’t believe me?

ZDNet reported in 2019 that 70% of Microsoft’s vulnerabilities were memory related.
How long has that trend lasted?

12 years.
Source: https://www.zdnet.com/article/microsoft-70-percent-of-all-security-bugs-are-memory-safety-issues/

C++ Evaluation

Now let’s evaluate C++ by these criteria.

C++’s Speed

Much like Rust, C++ is very close in speed to C’s performance. https://programming-language-benchmarks.vercel.app/cpp-vs-c
Like Rust, C++ is fast enough to be in this race.

C++’s Feature-Completeness

C++ has been feature-complete for a while now, and they keep adding features to it. Specifically, modern C++ (C++11 and later) has a lot of features that fix previous problems with using the language. For example, they’ve implemented new ways to manage memory, such as smart pointers and move semantics. They’ve also added a lot of quality-of-life things, such as for-each loops, lambdas, type inferencing, and a new threading library.

C++’s Development Tooling

I was a little bit surprised at C++’s tooling. I was under the impression that there wasn’t much more than make and Cmake. However, there are package managers, such as conan, vcpkg, and several others. There are at least 8 different compilers, 6 debuggers with several frontends for some of them, several sanitizers, a few linters, many profilers, some unit testing frameworks, great IDE support, LSP support, and more.

While there isn’t a monopoly in any of these features like there is in Rust, there are many options to choose from, allowing for a programmer to choose exactly what tooling matters to them.

Overall, I’m impressed, good job C++.

C++’s Industry Adoption

C++ is in everything and it is everywhere. It’s in game engines, MS office, photoshop, compilers, databases, the windows operating system, everything that runs fast.

If we were judging programming languages on their adoption alone, C++ might very well be the greatest language of all time.

C++’s Error Prevention

While C++ has made great strides in preventing errors with newer features like for each loops and unique pointers, it still isn’t perfect.

Specifically, there are still a lot of ways that you can still corrupt memory in C++, even using all the modern features. They’re loads better than old C++ sure, but the guarantees just aren’t as strong as what Rust is offering.

Evaluation

Before I get into my summary and what I chose, I just want to say that both of these languages are super strong, and I’m impressed with both of them. I’m impressed with Rust’s attempt to start fresh with a new memory model and modern features, and I’m impressed with C++’s ability to add features to address problems while maintaining backwards compatibility. Both of these are good languages, and I can understand why anyone would want to use either one. I have nothing but respect for both of these languages, and the people that choose them to build their products.

Here we can see speed compared between C++ and Rust: https://programming-language-benchmarks.vercel.app/cpp-vs-rust Both are super close to each other, with most tests being within a few ms of each other. Both are plenty fast, so let’s look at the other criteria.

Like speed, both Rust and C++ are what I would consider to be feature-complete. Neither one of those criteria are what I expected to make this decision based on, but it’s good to have some “disqualifying criteria” as a sanity check when making decisions. If your disqualifying criteria aren’t met, you cannot choose that option.

In development tooling, things get a little more interesting. Before researching this blog post, I would have thought rust would have won here hands down because of the ecosystem, however, it looks like C++ has made real strides here. There are lots of options for any development tooling I could want, so I’m going to announce this category as a draw.

Next, industry adoption.
This isn’t even close; C++ is by far the winner here.
That being said, it looks like rust is being adopted in a lot of very big and very famous C/C++ projects, like chrome and the Linux, and it looks like a lot of companies are experimenting with it in smaller greenfield projects as a replacement for C++. I didn’t know industry was that far along in adopting Rust. It still can’t compete with C++, but it’s no longer so early days that I would feel bad about running Rust in my tech stack for a new project.

Lastly, we have error prevention. Again, coming into this article I had a very different idea of what this section would have looked like. I didn’t know how much work modern C++ had done to make errors easier to catch. Unique pointers, smart pointers, for each loops, coroutines, and more have been added to help developers reason about the thornier aspects of the language. While some people might cringe at the bloat, I applaud this effort to make the language safer and nicer without breaking backwards compatibility.

So, just to recap:
TIED CATEGORIES:

  • speed
  • feature-completeness
  • development tooling

RUST WIN:

  • error prevention (by a smaller margin than I expected)

C++ WIN:

  • industry adoption (by a smaller margin than I expected)

However, that doesn’t mean that it’s a tie, it just means we get to choose what is more important to us: industry adoption or error prevention.

Let’s look at industry in my city, Vancouver.
Searching for rust developer jobs on indeed shows 25 results, and almost all of those are along the lines of “must have knowledge in 1 of the following languages: C, C++, Golang, Rust, python, Java.” A few are for rust jobs, but not many.

In contrast, C++ shows 391 jobs, and the first few that I look at are listed as being a C++ developer explicitly.

25 < 391

The Winner

For me, someone who is looking to grow their employable skills in the software industry, C++ is the winner, and that’s the language I will be using for Advent of Code this year.

Closing Thoughts

In the end, I chose C++ because it has such a strangle hold over industry. While doing my analysis, I learned that these two languages are much closer to feature parity with each other than I had previously thought.

I wouldn’t have felt bad choosing Rust either. Based on everything that I read I wouldn’t be surprised if in the next few years you start to see massive numbers of rust positions open up in industry.

Imagine you’re planning a new project at your workplace, and you do all the analysis that I did, and you see that Rust is basically a slightly less error-prone C++ with a slower compiler. It’s super loved and super hyped, so finding people that are at least decent with the language shouldn’t be that hard - just post on twitter and watch the job applications roll in. Shouldn’t you want to use a safer version of C++? That would be a very convincing argument to use it in your next project. I think that’s very likely what is going to happen in the next few years, and I think you’ll see a lot of technical designers choose Rust for those reasons.

So why did I choose C++ and not Rust, you may be asking. If that’s my grand prediction for the language after taking the hours to research and write about the language, why wouldn’t I make a bet on the future instead of the present?

And the answer, dear reader, is a simple one: I’m human and thus horrendously bad at predicting the future. My confidence rating in my prediction is 20% at the highest. It’s the same reason that I design my software for today’s problems, and do very little to optimize for tomorrow’s uncertain requirements. The road to hell is paved with premature optimization, and for me, learning Rust this year would be premature optimization.

See y’all on the advent of code leaderboards!