
Frustrated? It's not you, it's Rust - todsacerdoti
https://fasterthanli.me/articles/frustrated-its-not-you-its-rust
======
whatever_dude
Long but great article. Echoes my own track record with Rust.

I've been rewriting a project in Rust. The original is a 20+ years C project
(not created by me). Rewriting it in Rust has been a delight. So many
surprises, discoveries, learnings.

I've first converted the codebase using C2Rust (surprisingly efficient). The
code compiles and runs correctly. While Rust has been nagging me nonstop when
I try to do things the original C way, and I still have a lot of weird flags
on the code, once I rewrite some piece of code in idiomatic Rust, I end up
with a much better _design_ than before. Gone are weird linked lists, crazy
custom hashmaps, strings regurgitated in memory, "buffers" holding any manner
of data anywhere in memory. Instead, the new code is more efficient, more
understandable, and of course safer - even if more restrictive!

I've found at least two major _hidden_ bugs on the original codebase doing so
too.

Rust certainly has a learning curve. It's not C/C++ nor Java/C#/JavaScript.
But I'm more and more convinced it's the _right_ way to do things in what's
currently the C/C++ space.

~~~
blub
Surprisingly thin endorsement. The central argument seems to be that one has
gotten rid of custom data structures and raw buffers, but these are typical
for C and of course any language with higher abstraction power and a standard
library will have them in there.

In this sense you could have switched from C to almost anything else and have
gotten similar benefits. Finding bugs and improving the design is typical for
refactoring and redesign projects.

~~~
whatever_dude
The point here is using types that are still fast _and_ memory efficient
without having to resort to brittle pointer magic full of gotchas. You still
have raw buffers, and they're still efficient, but you just don't have to do
malloc or memcpy all over the place to make them work the way you want.

The way I see it, much of Rust, and this project specifically, is not about
moving to a higher abstraction... It's about moving to the _right_
abstraction.

Yes, I could have switched to just about anything else, and end up with an
even higher level code. But that would defeat the purpose of keeping it small,
fast, and memory conscious.

------
bsder
The one thing I wish I could do for people coming into Rust is hand them
"Programming Rust" and say "Read this. No, I mean it."

Rust is _NOT_ a Stack Overflow snippet language. Attempting to do so will get
you into trouble.

Rust does _NOT_ like pointer magic very much. If you try to be too clever with
pointers, you will fight with Rust.

That having been said, I really don't fight with Rust all that much. I don't
understand everyone complaining about the borrow checker, but, then, I've been
doing embedded C for a very long time now. So, a lot of my bad habits have
been ground out of me--quite often very painfully--by chasing subtle bugs in
production devices.

After a couple of those experiences, you begin to write _very_ different C
code.

~~~
moldavi
From what I've heard, the borrow checker is much more suited to low-level
programs like embedded programs, and for other kinds of programs, the borrow
checker is in the way a lot more. That could be why you don't understand the
complaining (if they are correct, that is).

~~~
bsder
I will also say that the compiler has gotten _MUCH_ better about flagging what
the real problem is over the last couple of years. Even 3 years ago, the error
messages were much less forgiving.

I also found that people tried to solve lifetime problems with the wrong
tools. Normally everybody reaches for & and mut and * in Rust but very few
people pointed out that an extra set of {} in the right place was more likely
to solve or illuminate the problem.

------
Waterluvian
I’ve been learning rust (and my first lower-than-python language) these past
six months by writing a game boy emulator (it can run Tetris!!!)

It’s been one of the least frustrating most satisfying programming experiences
of my life. I don’t think there’s a better language to learn while learning
how to write an emulator.

Combined with the plugin for vscode, it’s my wingman that points me in the
right direction whenever I want to do something stupid. The compiler errors
are amazingly descriptive for a newbie.

The limitations it puts on borrowing And sharing references forced my emulator
to take on a design I hadn’t planned. And completely unaware, months later,
I’m uncovering so many reasons why I’m so glad I was pressed to do it that
way.

~~~
blub
I'm not sure I understand how the design has ended up with a life of its own.
Are you saying that a design emerges without the intention of the programmer
just by using Rust?

What do you understand by design in this case?

~~~
Waterluvian
Im not the brightest bulb around but I’ll try.

I wanted a design where every subsystem (ppu, apu, serial, controller, etc.)
owned a reference to the singular MMU struct. This is how I’d do it in python.
Makes referencing mmu easier.

Rust said no, you can’t have many mutable references. I looked around and
found refcell and such. Ways to have shared mutability as long as I enforced
certain lifetimes and other guarantees that I’m not going to cause memory
problems by deleting what other systems expect to be there.

This was looking complicated and messy. Sure I could do it. But it spoke to
me: “this is probably not right”.

I ended up with a design where I have a core “step” function that calls each
system’s step function, in order, and passes in a mutable reference to MMU to
each. Basically it loans out the MMU one at a time.

The result is that testing is so much easier because all my systems are
stateless and my MMU holds all the state. I just assemble an MMU state the way
I want for each test and evaluate how the system mutated it.

It also meant that implementing save/restore state was incredibly easy because
my entire guest machine state was in one struct and all the systems were
stateless so they didn’t need any logic to recover state.

------
kanobo
Maybe it's better if beginners treat Rust the same way they would when
learning a new music instrument. For most people it's better to take lessons
early to avoid bad habits, and assume you know very little even if you know
another instrument very well.

------
arcticbull
> You're smarter than Rust. I'm not kidding!

You're probably not. That's kind of the thing. Rather, it's not that you're
not smarter, it's just that you're not used to doing things properly, and Rust
forces you to do things properly.

"Leave me alone, I know what I'm doing" says beginner juggling chainsaws on a
unicycle.

Ultimately it comes down to this: when you don't write down all the
information a compiler needs to generate an artifact, you're relying on
hidden, un-stated assumptions. Such assumptions are subject to change over
time. Relying on them isn't smart, it's dumb. It makes you _feel_ smart. Just
check the CVE list.

~~~
dragonsh
Another example from Rust community, without reading the article commenting
that Rust is always correct without any bugs or error and programmer is
stupid.

This attitude continuously drives me away from learning Rust, didn’t find such
attitude in Haskell or Lisp community which really took computer science and
art of programming forward unlike Rust, which is similar to other competing
niche languages.

~~~
doonesbury
Sometimes I get the impression from rust advocate articles on HN that they are
snobs. Not here; no way. This was well written, cheeky, thorough, and gave me
a solid sneak peak at doing rust from a c/c++/go/python/Java background. The
exacting standards of stopping data races at compile time is an exacting task.
I think I followed most everything here, although I wondered if the crossbeam
inclusion should be in language not library code ... But I don't know enough
to press further. Solving problems in libraries not language probably is
better.

Rust is one of few if only languages I am aware of that hit hard on data
safety without a gc. That'll make it quite different to the programmer.

~~~
fasterthanlime
I'm happy you enjoyed the article! I seem to remember scoped threads _were_
part of the standard library at some point, but they were eventually proved
unsound and removed.

I'm too lazy to go find a reference right now but it shouldn't be overly hard.

------
doonesbury
Hell of a good write up. Tx.

