<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>yttroxy.net</title>
		<link>https://www.yttroxy.net/blog</link>
		<description>
			Just a blog of whatever I've been thinking about recently.	
		</description>
		<language>en</language>
		<atom:link href="https://www.yttroxy.net/blog/feed.rss" rel="self" type="application/rss+xml" />
		<docs>https://www.rssboard.org/rss-specification</docs>
            <item>
                <title><![CDATA[Why I use Rust (and why I'm not a cult member)]]></title>
                <guid>why_i_use_rust.html</guid>
                <link>https://www.yttroxy.net/blog/why_i_use_rust.html</link>
                <pubDate>2026-07-12T20:00:00Z</pubDate>
                <description><![CDATA[
<h1>Why I use Rust (and why I'm not a cult member)</h1>
<h2>Background</h2>
<p>
I started programming when I taught myself a bit of C++, more because I had more time than I knew what to do with and was bored than anything else (the nickname hackerman in school might've also needed some
justification).
I'm not overly sure why I chose C++, I think I wanted to learn something closer to the metal to teach myself more about how computers worked and it looked slightly less painful than C
(although nowadays I think I enjoy writing C more).
</p>
<p>
After a while I got bored of C++, feeling that I'd learned all that was necessary (I knew next to nothing) I looked into other programming styles.
</p>
<h2>Haskell</h2>
<p>
I watched a few videos on programming paradigms, and came across Haskell (which looked more like a chicken had crawled over a keyboard into a text editor than a programming language) and was intrigued.
Mathematics has always been a strong point of mine, especially the more abstract side of things, so hearing that functional programming was based in abstract maths sounded perfect to me.
</p>
<p>
I very quickly realised I was slightly out of my depth with infinite lists, tail call elimination, and the dreaded <a href="https://en.wikipedia.org/wiki/Monad_(functional_programming)">monad</a>, so I turned to my
trusty YouTube and found <a href="https://www.youtube.com/@philipphagenlocher">Philipp Hagenlocher's channel</a>, which was remarkably helpful to me (even if I didn't understand what a monad was until years later).
I found that I really enjoyed this style of programming – although I found it hard to get anything actually useful done with it, the most useful thing I wrote in it was a horrifically over engineered script to
put thousand seperators in numbers.
I bought Philipp Hagenlocher's <a href="https://www.manning.com/books/learn-haskell-by-example">book</a> while it was in early access to give me something to do, which was fun to work through, I'd
recommend buying it if you're learning Haskell and have some spare money.
</p>
<p>
As any good Haskeller does, one of the first things I learned about was the <a href="https://wiki.haskell.org/Maybe">Maybe</a> monad. Despite not quite understanding what a monad was at the time, I realised very
quickly how valuable the Maybe construct is. Having to be explicit about if a value may not exist I think at least is one of the most critical features a language can have, fundamentally a value that is optional
must be treated very differently and losing this knowledge creates a massive opportunity for situations where you're pointlessly checking if a value that will always exist actually does, or worse, you're assuming
that an optional value will always be there. The Maybe monad singlehandedly convinced me of static typing (although accidentally passing the wrong variable to a function being a runtime error in Python should have
convinced me of that ages ago).
</p>
<p>
I found I got on well with the type class system, as a programmer, I don't really care about an inheritance hierarchy, it's mostly irrelevant to me what the "parent" class is,
it's relevant what I can do with the data that I have, which is precisely what type classes (and interfaces) are. I like this framing of a contract saying that the functionality on the data that I need is defined
a lot better than the inheritance/parent-child idea, although I do recognise the benefits of code reuse from being able to only <code>override</code> what's necessarily different between a parent and a child,
but I feel in practice outside of maybe things like GUI frameworks the benefits of this are slightly overblown.
</p>
<h2>C#</h2>
<p>
When I learned C++ I learned a little about the object oriented features (although found myself not using them that much), so C#'s object oriented nature wasn't a big struggle. What I did struggle with
initially was everything being a reference; in C++ I could tell when a function or method wasn't going to mess with a value based on the function signature taking a <code>const</code> reference or the argument by
value, in C# most things are reference types and are therefore passed by reference, without <code>const</code> references being a thing.
</p>
<p>
I quickly discovered that the Haskell way treating values as immutable and applying transformations to them genuinely made it easier for me to reason about programs and what they're doing,
it felt like the one of the biggest	changes coming from Haskell was that data and actions on that data were modelled together in a sort of anthropomorphising way –
the data <em>is</em> a <code>Person</code> and it <em>can</em> speak; whereas in Haskell the data and the transformations that could be applied to that data are seperate:
this is the data modelling a <code>Person</code> and we can take that data and produce some speech from it.
I have no idea why but Haskell's approach makes so much more sense to me as it made it easier for me to reason about where changes to the data were being made.
</p>
<p>
I did find writing GUI apps very pleasant compared to writing them in C++. The <code>async</code> system in C# is great (although I'm still not sure why <code>.ConfigureAwait(false)</code> isn't the default)
and WPF in Visual Studio is fairly nice to use (nowadays I tend to use <a href="https://avaloniaui.net/">Avalonia</a>), but this brings me to my next pain point.
</p>
<h3>Exceptions</h3>
<p>
Every language has to have some way of handling errors, C# uses exceptions. In theory they make a lot of sense: focus on the happy path of your program, while having a way to catch and handle errors where necessary.
I don't like exceptions. I find it infuriating not knowing for sure what functions/methods can throw, or if they even can at all. This <i>can</i> be solved with documentation, but in practice it isn't,
you might get documentation of what a method will throw itself, but it frequently doesn't include what the methods it calls can throw.
Even if the documentation is there, it's far too easy to ignore an exception that can be thrown and have a potentially unhandled error state that will only be found when some rare condition is encountered
(solid testing should find this, but not all testing is solid, and solid tests won't always find all error states).
</p>
<p>
Most of my issues here could be fixed with mandatory Java style fully checked exceptions. Oracle's guidance for checked exceptions in Java is
<q cite="https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html">If a client can reasonably be expected to recover from an exception, make it a checked exception.
If a client cannot do anything to recover from the exception, make it an unchecked exception.</q> I disagree with this, to me all exceptions should be checked exceptions. If the client wants to try to recover,
that's up to them, and they should be aware that this error condition is a possibility, if they don't they can always declare that their function can throw this exception too, maybe the caller can recover
afterall. I'm aware that this would take away some of the happy path focus and that not everyone's main goal is reliability, but adding some more exceptions to your function signature isn't a massive ask
and IDEs could probably just offer a quick action to add all exceptions necessary.
</p>
<h2>Rust</h2>
<p>
Eventually I found Nirvana, I became enlightened, I had seen the li… I'm messing, I'm not a cult member. I saw someone reference Rust somewhere and decided it sounded interesting enough to try. From what
I'd heard I was expecting some total nightmare with the borrow checker, but I found it actually mapped quite well to how I write programs anyway. I think the way I learned C++ initially made me very conscious
of object lifetimes and how <abbr title="Resource Aquisition is Initialisation">RAII</abbr> works, so the only major pain point was when there's more of a graph relationship between objects (e.g.
doubly linked lists), although in a lot of cases this can be architected around or avoided with <code>Rc&lt;T&gt;</code>.
</p>
<h3>What I like</h3>
<p>
Having either one live mutable reference xor many live immutable references gave me the ability to reason about the program in a similar way to Haskell's immutability, with a bit more of the procedural flexability
that's necessary for practical software development (it took me an embarassingly long time to realise if you want a short lived mutable reference you can just wrap it in a scope where there are no
current immutable references). I also like how arguments are passed to functions, you either move a value (the caller can choose to clone the value if they want pass by value semantics) or pass by immutable
or mutable reference, the function signature gives you all the information of what the function can do with the value.
</p>
<p>
The type system gives me assurances that I know what exactly I'm working with. Discriminated unions (<code>enum</code>) and pattern matching
make for an incredibly pleasant experience and are a feature I sorely miss when I use C# (I have been known to bastardise records and inheritance to form something similar though), and an object's thread safety
being built into its type is genius.
The trait system gives me all I need from the Object Oriented world, I can define contracts between my functions and the data that's needed,
I can even have some polymorphism with the <code>Box&lt;dyn Trait&gt;</code> pattern. This is a style thing, but I do like the seperation of the <code>struct</code> and the <code>impl</code> sections,
to me it makes sense that the data and the actions on the data are seperately grouped.
</p>
<p>
Rust's iterators are also a joy to use, I don't know why but the idea of taking a collection zipping it with another one, mapping functions to it, filtering it down, and folding over it to get a result is so
much easier for me to read and reason about than the imperative equivalent. The language as a whole makes me feel like I've got everything I need to write the programs I want to in the way that makes the most
sense to me.
</p>
<h3>Where it falls down</h3>
<p>
GUI programming is a bit of a mess. It doesn't map nicely to the ownership system, so you end up with a lot of <code>Rc&lt;RefCell&lt;T&gt;&gt;</code>, which isn't inherently a problem but it's clear you're fighting
the language a little. I've recently had more success with <a href="https://slint.dev/">Slint</a> although I'm still not altogether happy with it.
</p>
<p>
I love that the language sets out a contract for what an asynchronous executor needs to do, then leaves the programmer free to choose one and use that in their project, but in practice most crates you'll
use expect <a href="https://tokio.rs/">Tokio</a>, which is great although it's not the smallest thing ever and comes with a lot of features that may well be overkill for what's needed.
</p>
<p>
I like the error handling by <code>Result</code> instead of exceptions, but it's all to common to see <code>Result&lt;T, Box&lt;dyn Error&gt;&gt;</code>, which causes a lot of the same issues as I see in exceptions.
I would like it if I could somehow specify <code>Result&lt;T, std::io::Error + MyError&gt;&gt;</code> and the language would basically create an anonymous <code>enum</code> which could be matched against, my
current solution is just manually creating these enums, which causes a bit of an explosion of one off <code>enum</code> definitions.
</p>
<p>
I do also worry slightly about it suffering from feature creep in the way C++ (and to a lesser extent C#) has, where everyone only understands their own subset of such an incomprehensibly large language.
I think it's less sucepitble to this compared to C++ due to its more opinionated nature and clearer focus, but I hope lessons have been learned from the past in this regard.
</p>
<h3>Conclusion</h3>
<p>
I love Rust, although it's clearly not good for every problem: it'll never replace scripting languages or be as quick to prototype as something like Python, but in a way that's the point. If you want to develop
reliable, readable software, that's genuinely pleasant to write, I've found nothing better than Rust. I don't think the killer feature for most developers is the borrow checker, I think it's the zero cost
abstractions, the developer experience, and the way the language guides you to writing reliability.
</p>
                ]]></description>
            </item>
	</channel>
</rss>
