News for hackers. Stuff that matters.
Re:Rust 2024 the Year of Everywhere? by nu11ptr on Thursday September 22, 2022 @10:48PM (#32947441)
This exactly how I felt the first two times I tried it, but I never really just dove in. The third time I just dove in. The learning curve is straight up, but once you are over (took me about a month), Rust isn't really all that hard. I can write it as fast as I can write Python typically, so that friction you probably feel will go away...entirely. Sure, there are a few corner cases where the type system gets hard and the more you care about every cycle of performance the more of those you have, but if you are just looking to code Rust as a high level language, it really isn't that hard. Knowing that everything is likely to work when it compiles is really good feeling too.

Tips/Concepts:

- Form a mental model of the rules/memory model of the language, this will help you get to an understanding, and once you understand you don't have to remember the rules.. you could write them yourself.

- The analogy I used to understand borrowing: it is like a read/write lock. Any data structure can be read any number of times (&), but it can only be written once at a time (&mut)

- Borrowing "locks" the position of the data structure and this is one of my favorite features. Imagine you have a reference to the middle of a data structure and then it suddenly moves... this can't happen in Rust as borrows "lock" the struct from moving

- Lifetimes aren't magic and you are in no way defining the lifetimes themselves with lifetime annotations. All you are doing is helping the compiler see which references are backed by what values already. Once you understand which these are lifetimes become easy.

- Eventually you will have an aha moment.. and you will wonder what was so hard. You will have to think about memory in a lower level way, but only to learn it, after that it is just natural

Re:Rust 2024 the Year of Everywhere? by verdagon on Thursday September 22, 2022 @11:28PM (#32947677)
In my experience learning Rust (and in watching others learn Rust) that first "aha!" moment is actually rather misleading.

That moment comes when one learns how to technically accomplish any task in Rust. One knows the minimum set of tools needed to refactor enough to work around the borrow checker's limitations. Learning what the borrow checker prefers becomes second nature and, as you say, becomes natural.

However, the journey isn't over there. One still has to learn the costs they paid to fit their design into what the borrow checker prefers. For some situations, the cost is low (CLI tools, data transformation, numeric analysis, etc). For other situations, the cost can be alarmingly high: one learns that the borrow checker is surprisingly anti-abstraction, causes brittle APIs, and can sometimes introduce artificial complexity compared to the optimal solution in other languages. One sees this a lot in programs with unavoidable inherent state. There are also sometimes problems working with teams, because the borrow checker likes to cause refactors with very wide blast radii that conflict with others.

Of course, this varies wildly person-to-person, according to the prevalent use of unsafe, Rc, etc.

Understanding how to work within the borrow checker isn't enough. The real challenge comes in figuring out when to work within it, and when to work outside it, in my opinion.

Re:Rust 2024 the Year of Everywhere? by kibwen on Friday September 23, 2022 @12:08AM (#32947936)
> The real challenge comes in figuring out when to work within it, and when to work outside it, in my opinion.

You don't need to feel bad about "working outside" the borrow checker, and maybe that's a signal that needs boosting. I've been using Rust for ages and I'm not averse to cloning things when I need to. It's cool that you can create zero-allocation libraries by threading lifetimes everywhere, and I certainly appreciate all the library authors who go the extra mile by doing so internally to their libraries, but in my application code it's easy to tell that a given thing isn't going to be a bottleneck and isn't going to be negatively impacted by a little copying and allocating.

Re:Rust 2024 the Year of Everywhere? by pdimitar on Friday September 23, 2022 @05:22AM (#32949647)
Yep, very much this. I code async CLI apps and I seriously don't care that the CLI args and the data structures they get transformed to are cloned 250 times at startup because after that 99% of the actual heavy-duty code is working with channels and references with nearly zero memory pressure. Memory usage gets bumped up by about 2% after the first 1-2 minutes of operation and it stays constant for next 11 hours during which I've monitored it.

I don't even need to benchmark anything. The apps are working ultra fast on a Celeron J450 CPU at ~20MB RAM usage and barely hit 10% CPU (since they're mostly network-bound).

No need for premature optimization. I haven't dived in the lifetime hell of Rust yet but I'm already quite productive and I will only be using zero-allocation techniques if my current code proves inadequate the the ever-increasing demand that these apps will soon face.

Re:Rust 2024 the Year of Everywhere? by mwcampbell on Friday September 23, 2022 @10:53AM (#32952740)
I figured that working outside the borrow checker meant using unsafe.
Re:Rust 2024 the Year of Everywhere? by int_19h on Saturday September 24, 2022 @01:27AM (#32959942)
That's just the most obvious smell. But this also happens if you start passing indices around, using them much like unchecked pointers.
Re:Rust 2024 the Year of Everywhere? by echelon on Friday September 23, 2022 @11:45AM (#32953503)
Or interior mutability. Or sync+send. Or...

There are lots of ways to shape your solution.

Re:Rust 2024 the Year of Everywhere? by bsder on Thursday September 22, 2022 @11:51PM (#32947833)
> This exactly how I felt the first two times I tried it, but I never really just dove in. The third time I just dove in. The learning curve is straight up, but once you are over (took me about a month), Rust isn't really all that hard.

I will say that the compiler got WAY better over the last couple of years.

The quality of the error messages went way up, and the number of times I had to do something stupid because the compiler couldn't infer something went way down.

To me, the compiler getting so much better was what finally got me over the hump.

Re:Rust 2024 the Year of Everywhere? by aussiesnack on Thursday September 22, 2022 @10:53PM (#32947473)
> Rust isn't really all that hard.

You don't find it hard. Many do.

Re:Rust 2024 the Year of Everywhere? by kibwen on Thursday September 22, 2022 @11:01PM (#32947522)
Yes, Rust is quite different from typical languages thanks to ownership and borrowing. It often takes people several attempts to learn it before their perspective shifts and it finally clicks for them. But this perception of Rust has less to do with Rust being "hard" than it has to do with Rust being "different". To be sure, Rust has hard parts even after you've internalized the differences, but IMO by that point it's not substantially different from mastering the hard parts of other languages (especially other systems languages, none of whom can get away with entirely sweeping the details of the machine under the rug).
Re:Rust 2024 the Year of Everywhere? by nu11ptr on Thursday September 22, 2022 @11:07PM (#32947549)
I can see how it could be hard for someone used to high level languages and who doesn't care about how memory actually works "under the hood". The secret to learning Rust is really the same as C/C++: you have to learn to think of memory in a low level way -and- learn Rust's safety rules for dealing with that. I think it does take someone very dedicated to the task, more so than is required to learn say Python, for example. However, I find it much more rewarding.
Re:Rust 2024 the Year of Everywhere? by aussiesnack on Friday September 23, 2022 @01:25AM (#32948369)
I don't think the ownership model, borrowing, references etc are actually particularly difficult. They're well explained in "The Book", even better so in Jim Blandy's "Programming Rust", and at least in principle can be got over in an afternoon. Admittedly it can all knotty with a lot of closures and async etc, but it's certainly not the source of the difficulties for me.
Re:Rust 2024 the Year of Everywhere? by bsder on Friday September 23, 2022 @12:00AM (#32947888)
> You don't find it hard. Many do.

The question at the end of the day is whether that "hardness" is required or accidental. My gut feel is that Rust does have some accidental complexity--poor support for static/globals, poor support for placement new and alternate allocators, inability to transmute equivalent types well, etc.

However, my gut feel is also that a lot of Rust's "difficulty" is the fact that people really don't know how to program C/C++ even remotely correctly, and Rust is simply slapping them in the face with that fact.

Re:Rust 2024 the Year of Everywhere? by kibwen on Friday September 23, 2022 @12:10AM (#32947954)
*> poor support for static/globals

I'll agree with your other things, but discouraging global state is an aspect that reduces ultimate complexity, rather than increasing it. :P

Re:Rust 2024 the Year of Everywhere? by jandrewrogers on Friday September 23, 2022 @01:10AM (#32948290)
It increases complexity if the state is intrinsically global. Hardware resources, for example, which are commonly directly managed in systems code, are intrinsically global state. You can't allocate another hard drive or physical network interface. I've seen impressively convoluted code that existed solely to pretend that global state isn't actually global state, because that was seen as bad, even though it behaved exactly like global state.
Re:Rust 2024 the Year of Everywhere? by tialaramex on Friday September 23, 2022 @07:20AM (#32950354)
Rust is comfortable with immutable statics. The existence of a global readable Doodad is no problem. For mutable access static Doodad Rust requires unsafe, because you will probably shoot yourself in the foot.

Imagine there's a static NetworkIF nic which is immutable. Maybe we can call predicates like nic.up() to find out if this interface is up, or nic.packet_counts() to get some statistics about packets. But it's immutable, so we can't call nic.change_addr() or nic.disable_packet_filters() as those require mutation. If it was mutable we'd need unsafe Rust to try to call those, because doing so means being very careful about who does what and when they do it or we'll get in a mess.

Because of "interior mutability" we can have a Rust static which is immutable from a Rust point of view, and thus safe, but where we can get at mutable internals. For example static Mutex<NetworkIF> nic. Now it's protected by a mutex. We can lock the mutex, and thus get mutable access to the NetworkIF, until we release that lock. If somebody else has the lock then we'd block waiting for them to release it.

With just mutable globals everywhere and a larger team it's easy to end up with clashes where two subsystems both think they "own" a shared mutable object and treat it accordingly then are surprised that this doesn't consistently do what they expected.

Re:Rust 2024 the Year of Everywhere? by bsder on Friday September 23, 2022 @05:12PM (#32957140)
As in all things--sometimes.

One thing in particular that is gratuitously difficult in Rust is to do some very expensive runtime initialization, place the result into static memory, and then do read-only things to that memory after it is initialized.

Rust really does not like that pattern (it always wants you wrap that and takes locks to it with the associated performance hit) and yet it is an extremely common thing to need to do (embedded communication stacks, graphics card shaders, etc.).

Re:Rust 2024 the Year of Everywhere? by sam0x17 on Friday September 23, 2022 @01:10AM (#32948286)
global state is often necessary. Abusing it is always possible, but every startup-sized application footprint I've ever been in we eventually have to add an exception to the no-globals linting rule for some very legitimate reason in some specific place.

The crate ecosystem (oncecell, lazystatic) lets you completely sidestep this limitation for now anyway before better const behavior eventually gets added to stable

Re:Rust 2024 the Year of Everywhere? by qalmakka on Friday September 23, 2022 @02:59AM (#32948861)
The point is, Rust is vastly easier than C++ when you start factoring in the complexity of debugging nasty design choices that comes to bite you in the back and you can't really fix without tearing the whole application apart.

Yesterday I was fighting the borrow checker because it wasn't allowing me to pass a reference in an async function. After a while it dawned me that if that thing I was attempting to write would have been accepted, it would have caused a crash in some rare, but not impossible, circumstances.

It saved me potentially countless hours of debugging and wrapping my head around the fact that my smart abstraction crashed every once in a while, something that happens to me everyday with C++.

Rust is hard, but it's less hard than it's alternatives.

Re:Rust 2024 the Year of Everywhere? by pjmlp on Friday September 23, 2022 @04:11AM (#32949239)
Dunno, maybe it is Stockholm syndrom from using C++ since 1993, but I definitly find easier to understand template metaprogramming than the upcoming GAT, or the whole Pin and PhatomData stuff.
Re:Rust 2024 the Year of Everywhere? by Ygg2 on Friday September 23, 2022 @05:20AM (#32949638)
Sure, but you are comparing meta programming facility to a type/lifetime feature that serves as Higher Kinded Type replacement.

In Rust same thing holds, macros are easier than GAT

I don't get why PhantomData or Pin are that hard to grasp?

PhantomData is just a type marker that has no purpose other than help compiler. See https://doc.rust-lang.org/nomicon/phantom-data.html

Pin is a way to create self referential structs, by pinning memory and preventing moves.

PhantomPinned is a marker type to ensure your type is not Unpin (it is by default). Unpin it thing that shouldn't be pinned, like bool, i32, etc.

Re:Rust 2024 the Year of Everywhere? by qalmakka on Friday September 23, 2022 @05:24AM (#32949653)
> Pin is a way to create self referential structs, by pinning memory and preventing moves.

This, exactly. Pin works more or less like a C++ class with a deleted move constructor. Copies may be allowed if clone/copy (aka, the implicit/explicit copy constructor) are defined, but move and RVO are not.

Lots of Rust's concepts can often be described in terms of C++'s techniques, but more often than not in C++ it tends to be a hack, while Rust has a formalism for that, like Pin for instance. In C++ you can have moveable self-referencing structs because you can update the self references in the move constructor, but moves in Rust are always memcpy - which is saner IMHO than the whole move constractor and rvalue shenanigans.

Re:Rust 2024 the Year of Everywhere? by ridiculous_fish on Friday September 23, 2022 @02:57PM (#32955709)
How does this work? I want to wrap POSIX semaphores. You call sem_init, passing it the address of an int; later you call sem_destroy and pass it the same address. So the location of the int must not change.

In C++ you would delete the move constructor:

    struct sema { 
        int v;
        void sema(sema &&) = delete;
    };
In Rust you might try this, but it doesn't work:

    struct Sema {
        v: Pin<i32>,
    }
there is no way to create a "Pin<i32>". The closest you can get is probably to malloc it:

   struct Sema {
       v: Pin<Box<i32>>
   }
but now Pin is adding nothing at all (except perhaps a hint to the reader) and may be deleted. The real guarantee is provided by Box, not Pin.

It looks to me like Pin is created to support async, and outside of that use case is not very useful, and is a poor replacement for non-movable types.

Re:Rust 2024 the Year of Everywhere? by Ygg2 on Friday September 23, 2022 @05:19PM (#32957209)
> there is no way to create a "Pin<i32>"

Caveat, I haven't worked with Pin that much. Take this with a grain of salt.

My understanding is - you really shouldn't put copyable stuff in Pin. Period. If you want something like that wrap i32 in new struct and declare it !Unpin. Since negative traits are unstable, you just write PhantomPinned marker

   struct NonPinI32 {
       v: i32,
       non_pin: PhantomPinned,
   }
Re:Rust 2024 the Year of Everywhere? by steveklabnik on Friday September 23, 2022 @06:13PM (#32957733)
pin is purely a property of a pointer, so Pin<i32> doesn’t make sense.

While you’re right that Box gives you a stable address, you can still move out of a Box, or swap something into the Box. Pin<Box<P>> prevents that.

Re:Rust 2024 the Year of Everywhere? by pjmlp on Friday September 23, 2022 @05:42AM (#32949771)
I am only listening some of the concepts that I find harder to grasp, regardless of the context.

Macros are easier than GAT, maybe, there is a whole talk how serde goes crazy with macros.

PhantomData or Pin are hard to grasp, not as concept, rather to keep track when they are needed, many times it isn't clear that the way to fix some compilation error is to plug one of those types. A bit like having to do references to constant literals as well, another gotcha.

Re:Rust 2024 the Year of Everywhere? by estebank on Friday September 23, 2022 @07:46AM (#32950579)
If you encounter a case where the solution to a problem was PhantomData or Pin, and the compiler doesn't flat out tell you that, file a ticket.
Re:Rust 2024 the Year of Everywhere? by Ygg2 on Friday September 23, 2022 @08:30AM (#32951004)
> PhantomData

Usually when you want to give type some information it wouldn't normaly have. Like e.g. using it to store generic type signature for some kind of SQL builder. or to keep a lifetime that would otherwise be unbound.

> Pin

Just for self-referential structs. Since async relies on self-referential, it might also require it.

---

When to use it? When you either exhaust all other options or know enough to judge it worthwhile.

Re:Rust 2024 the Year of Everywhere? by qalmakka on Friday September 23, 2022 @05:22AM (#32949642)
I've seen people picking up C++ from scratch recently and rest assured, that's not so obvious for a novice like it is for a person that's been using it for decades. I think the level of complexity is similar, but at least Rust features feel like they were designed on purpose.

C++ metaprogramming, to be fair, is a happy little accident that turned out being a blessing, more than something that was well designed from the start...

Re:Rust 2024 the Year of Everywhere? by darthrupert on Friday September 23, 2022 @12:56AM (#32948216)
> Rust isn't really all that hard. I can write it as fast as I can write Python typically, so that friction you probably feel will go away...entirely.

I hear this a lot. Having written both, it seems to me that the only way to reasonably have this thought is that one never learned to use the repl in Python. This gives me a, say, 2-10x improvement in implementation speed, at least for exploratory-kind of coding.

Re:Rust 2024 the Year of Everywhere? by chrismsimpson on Thursday September 22, 2022 @11:25PM (#32947660)
You’re holding it wrong