Learning to program in rust
-
I’m a OOP programmer.
I wrap everything within
Arc<Mutex<>>
.I’m a happy dev.
wrote on last edited by [email protected]I mean yah. That’s what it takes. But like when I try to write code around Arc<_> the performance just tanks in highly concurrent work. Maybe it’s an OOP rust skill issue on my end. Lol.
Avoiding this leads, for me at least, to happiness and fearless, performant, concurrent work.
I’m not a huge fan of go-lang but I think they got it right with the don’t communicate by sharing memory thing.
-
I mean yah. That’s what it takes. But like when I try to write code around Arc<_> the performance just tanks in highly concurrent work. Maybe it’s an OOP rust skill issue on my end. Lol.
Avoiding this leads, for me at least, to happiness and fearless, performant, concurrent work.
I’m not a huge fan of go-lang but I think they got it right with the don’t communicate by sharing memory thing.
You mean mutex? Arc allows synchronous read only access by multiple threads, so it's not a performance bottleneck. Locking a mutex would be one.
-
Skill Issue.
For reals though adopting a functional style of programming makes rust extremely pleasant . It’s only when people program in object oriented styles that this gets annoying.
No loops, and no state change make rust devs happy devs.
I just started learning rust like two days ago and I haven’t had too many issues with OOP so far… is it going to get considerably worse as the complexity of my projects increases?
-
I just started learning rust like two days ago and I haven’t had too many issues with OOP so far… is it going to get considerably worse as the complexity of my projects increases?
You’ll be fine. You will learn the lifetime stuff and all will work out. It’s not that bad to be honest.
-
You mean mutex? Arc allows synchronous read only access by multiple threads, so it's not a performance bottleneck. Locking a mutex would be one.
wrote on last edited by [email protected]I mean it could be Mutex, or Rwlock or anything atomic. It’s just when I have to put stuff into an Arc<> to pass around I know trouble is coming.
-
Me, every time I try searching a Rust question.
That's easy. Just do:
fn is_second_num_positive() -> bool { let input = "123,-45"; let is_positive = input.split(',') .collect::<Vec<&str>>() .last() .unwrap() .parse::<i32>() .unwrap() .is_positive(); is_positive }
-
I just started learning rust like two days ago and I haven’t had too many issues with OOP so far… is it going to get considerably worse as the complexity of my projects increases?
Worse in the sense of more errors, sure, but as you go you’ll pick up more of the rust patterns of thinking and imo it’s very worth it. It’s an odd blend and can be a bit verbose but I definitely prefer it to a pure OO or pure functional style language personally
-
This post did not contain any content.
Learning C, that smasher would never have stopped.
-
Me, every time I try searching a Rust question.
That's easy. Just do:
fn is_second_num_positive() -> bool { let input = "123,-45"; let is_positive = input.split(',') .collect::<Vec<&str>>() .last() .unwrap() .parse::<i32>() .unwrap() .is_positive(); is_positive }
Can't resist pointing out how you should actually write the function in a "real" scenario (but still not handling errors properly), in case anyone wants to know.
If the list is guaranteed to have exactly two elements:
fn is_second_num_positive_exact(input: &str) -> bool { let (_, n) = input.split_once(',').unwrap(); n.parse::<i32>().unwrap() > 0 }
If you want to test the last element:
fn is_last_num_positive(input: &str) -> bool { let n = input.split(',').next_back().unwrap(); n.parse::<i32>().unwrap() > 0 }
If you want to test the 2nd (1-indexed) element:
fn is_second_num_positive(input: &str) -> bool { let n = input.split(',').nth(1).unwrap(); n.parse::<i32>().unwrap() > 0 }
-
I just started learning rust like two days ago and I haven’t had too many issues with OOP so far… is it going to get considerably worse as the complexity of my projects increases?
It will become more complex when you start needing circular references in your datastructures.
-
Learning C, that smasher would never have stopped.
It would also be emitting significantly less helpful messages.
-
It would also be emitting significantly less helpful messages.
wrote on last edited by [email protected]"What messages?"
Lol yes
-
Can't resist pointing out how you should actually write the function in a "real" scenario (but still not handling errors properly), in case anyone wants to know.
If the list is guaranteed to have exactly two elements:
fn is_second_num_positive_exact(input: &str) -> bool { let (_, n) = input.split_once(',').unwrap(); n.parse::<i32>().unwrap() > 0 }
If you want to test the last element:
fn is_last_num_positive(input: &str) -> bool { let n = input.split(',').next_back().unwrap(); n.parse::<i32>().unwrap() > 0 }
If you want to test the 2nd (1-indexed) element:
fn is_second_num_positive(input: &str) -> bool { let n = input.split(',').nth(1).unwrap(); n.parse::<i32>().unwrap() > 0 }
Can still use
.is_positive()
, though... -
I think the problem is that many introductory examples use
unwrap
, so many beginner programmers don’t get exposed to alternatives likeunwrap_or
and the likes.Yeah, we onboarded some folks into a Rust project last year and a few months in, they were genuinely surprised when I told them that unwrapping is pretty bad. Granted, they probably did read about it at some point and just forgot, but that isn't helped by lots of code using
.unwrap()
either. -
I just started learning rust like two days ago and I haven’t had too many issues with OOP so far… is it going to get considerably worse as the complexity of my projects increases?
The thing with OOP, particularly how it's used in GCed languages, is that it's all about handing references out to wherever and then dealing with the complexity of not knowing who has access to your fields via getters & setters, or by cloning memory whenever it's modified in asynchronous code.
Rust has quite the opposite mindset. It's all about tracking where references go. It pushes your code to be very tree-shaped, i.e. references typically¹ only exist between a function and the functions it calls underneath. This is what allows asynchronous code to be safe in Rust, and I would also argue that the tree shape makes code easier to understand, too.
But yeah, some of the patterns you might know from OOP will not work in Rust for that reason. You will likely need to get into a different mindset over time.
Also just in case: We are talking OOP in the sense of the paradigm, i.e. object-oriented.
Just using objects, i.e. data with associated functions/methods, that works completely normal in Rust.¹) If you genuinely need references that reach outside the tree shape, which is mostly going to be the case, if you work with multiple threads, then you can do so by wrapping your data structures in
Arc<Mutex<_>>
or similar. But yeah, when learning, you should try to solve your problems without these. Most programs don't need them. -
"What messages?"
Lol yes
Segmentation fault?
-
This is my experience every time I return to learning rust. I’m guessing that if I used it more often than once a quarter with hobby projects I’d stop falling into the same traps.
I find that the error messages themselves are a great tool for learning when it comes to Rust.
-
I find that the error messages themselves are a great tool for learning when it comes to Rust.
Eh, I’m not entirely sold on that idea.
I think they do a good job of pointing out “this is a behavior/feature of Rust you need to understand.” However they can send you down the wrong path of correction.
The compiler error mentioning static lifetime specifiers of
&str
demonstrates both. It indicates to the developer that ownership and scopes will play a significant role when defining and accessing data. The error though will guide them towards researching how to define static lifetimes and possibly believe that they will need to set this in their functions and structs. Each time you look at questions about this error in places like Stack Overflow with example code you’ll find suggested solutions explaining that a manually-defined static lifetime isn’t necessary to resolve the problem. -
This is my experience every time I return to learning rust. I’m guessing that if I used it more often than once a quarter with hobby projects I’d stop falling into the same traps.
Yeah, these become a lot less relevant with routine.
-
Avoiding the main-thread panicking is mostly just a matter of not using
.unwrap()
and.expect()
. -
String
vs.&str
can mostly be solved by generally using owned datatypes (String
) for storing in structs and using references (&str
) for passing into function parameters. It does still happen that you forget the&
at times, but that's then trivial to solve (by just adding the&
). -
"temporary value dropped while borrowed" can generally be avoided by not passing references outside of your scope/function. You want to pass the owned value outside. Clone, if you have to.
-
"missing lifetime specifier" is also largely solved by not storing references in structs.
-
-
Can't resist pointing out how you should actually write the function in a "real" scenario (but still not handling errors properly), in case anyone wants to know.
If the list is guaranteed to have exactly two elements:
fn is_second_num_positive_exact(input: &str) -> bool { let (_, n) = input.split_once(',').unwrap(); n.parse::<i32>().unwrap() > 0 }
If you want to test the last element:
fn is_last_num_positive(input: &str) -> bool { let n = input.split(',').next_back().unwrap(); n.parse::<i32>().unwrap() > 0 }
If you want to test the 2nd (1-indexed) element:
fn is_second_num_positive(input: &str) -> bool { let n = input.split(',').nth(1).unwrap(); n.parse::<i32>().unwrap() > 0 }
wrote on last edited by [email protected]Even better to use
expect
with a short message of what the assumption is: "the string should contain a comma" if it ever panics you'll know exactly why.