this post was submitted on 08 Oct 2023
65 points (92.2% liked)

Rust

6117 readers
10 users here now

Welcome to the Rust community! This is a place to discuss about the Rust programming language.

Wormhole

[email protected]

Credits

  • The icon is a modified version of the official rust logo (changing the colors to a gradient and black background)

founded 2 years ago
MODERATORS
you are viewing a single comment's thread
view the rest of the comments
[–] [email protected] 12 points 1 year ago (14 children)

Rust requires a mindset shift

That's easier said than done. I find that there's no clear vision of what "idiomatic" Rust is. With functional programming, it feels like there's a strong theoretical basis of how to structure and write code: pure functions everywhere, anything unpure (file access, network access, input conversion, parsing, etc.) goes into a monad. TBF, the only functional code I write is in JS or nix and nix-lang is... not really made for programming, nor is there any clear idea of what "good" nix code looks like.

Rust however... are Arc, Box, Rc, async, etc. fine? match or if/else? How should errors be handled? Are macros OK? Yes, the clippy linter exists, but it can't/won't answer those questions for you. Also the fact that there is no inheritance leads to some awkward solutions when there is stuff that is hierarchical or shares attributes (Person -> Employee -> Boss -> ... | Animal -> Mammal-Reptile-Insect --> Dog-Snake-Grasshopper). I haven't found good examples of solutions or guidance on these things.

My rust code still feel kludgy, yet safe after a year of using it.

[–] Solemarc 1 points 1 year ago (2 children)

If you want inheritance you can add structs as parameters of other structs. This will also allow them to use impl functions for that struct.

As far as I understand it Arc<> is just the Async version of RC<>.

I'm not entirely sure about Box<> and a lot of its API's are still unstable but I believe it's primarily used as an owner for unsafe things.

[–] [email protected] 4 points 1 year ago* (last edited 1 year ago) (1 children)

As far as I understand it Arc<> is just the Async version of RC<>.

Not quite right. Arc is the atomic RC, aka the one that is thread safe and can thus can be sent to other threads. Rc is single threaded only. async is agnostic of threading and there exists runtimes that are both multithreaded and single threaded.

Although tokio, the most common async runtime, is multi threaded and so tasks you create need to be multi-threaded safe thus you likely need to use Arc for most things in tokio. But that is due to the multithreaded nature of tokio, not the fact it is async.

I’m not entirely sure about Box<> and a lot of its API’s are still unstable but I believe it’s primarily used as an owner for unsafe things.

Box is the single ownership heap allocated datastucture of rust. It is a core type that is used for a lot of things. It is not just for unsafe things and mostly safe things are put in a Boxes. It is basically used whenever you want something on the heap rather than the stack At least when the type in question is not already heap based (like Strings, Vec, Arcs etc).

It is used a lot for trait objects (when the type is only known at runtime, not compile time, aka Box&lt;dyn Trait>/&amp;dyn Trait) when you need ownership of the object (aka reference trait objects are not suitable). Or when you have a large type that needs to be moved around a lot and you don't want expensive stack copies when a cheap copy of a pointer to some heap data will do instead. Or you have a type that is not Sized (aka the size is not known at compile time and needs to be tracked at runtime) but need it to be owned (such as a slice, trait objects etc).

[–] Solemarc 1 points 1 year ago

Ahh, thank you for the corrections.

[–] sleep_deprived 3 points 1 year ago

Box is (basically) just the way to have memory on the heap. Here's a direct comparison of how to do heap memory in C/++ and in rust:

int* intOnHeap = (int*)malloc(sizeof(int));
*intOnHeap = 0;
MyClass* classOnHeap = new MyClass();
let intOnHeap: Box = Box::new(0);
let structOnHeap: Box = Box::new(MyStruct::default());

There can be a bit more to it with custom allocators etc. but that's the only way most people will use boxes. So Box basically just means "a T is allocated somewhere and we need to free that memory when this value is dropped".

load more comments (11 replies)