Live data from Hacker News

Rust for Professionals

overexact.com

71–80 of 103 posts

Re: Rust for Professionals

#71

Earlier quoted context omitted.

I found the copy/move situation in Rust to be far less intuitive than in C++. In C++, move semantics are obvious because they rely on std::move and the && operator, whereas in Rust, similar behavior seemed to depend on the object type. Even more confusingly, Rust has its own move operator as well, despite destructive move being the default behavior for assignment. I found it frustrating enough that I put the language…

> In C++, move semantics are obvious because ... In Rust it's also obvious because every = is a move. Confusion comes from tutorials pretending for too long that it's not. > whereas in Rust, similar behavior seemed to depend on the object type. It's best to think of that as an exception to the rule created specifically for numbers and other similar small, cheaply copied things. If you need to move `a` but `a` has a t…

  > In Rust it's also obvious because every = is a move.
False, depending on the presence of an explicit type annotation on the left-hand side, an = triggers either a move or a reborrow.

Re: Rust for Professionals

#72
post #50

Nice blog post. Nonetheless, to a new learner like me, the hardest part of rust is not its syntax; it is the ownership management. Sometimes I easily know how to implement a task efficiently in other languages but I have to fight the compiler in rust. I either need to reorganize data structures, which takes effort, or to make a compromise by cloning objects, which affects performance. Note that I do agree with rust d…

This is exactly why I prefer Rust, eh, for everything. It forces you to think harder about your data structures and to better organize/understand your program and how data flows, gets consumed and get output. You can ignore that in other languages, but this comes at a cost later.

My experience with Rust data structures is the opposite. To satisfy lifetime analysis inherent in pointer-based data structures, users tend to introduce additional indirection. For example, mapping keys to indexes, and then indexes to array elements, instead of simply mapping keys to values.

Re: Rust for Professionals

#73
post #16

any constructive criticism on rust syntax?

I don't like how

fn func() means that 'a must outlive execution time of func

but

T:'a means that references contained in T must live longer than 'a

and

'a:'b means 'a must live longer than 'b (that's consistent at least)

Maybe:

    fn 'a:func() {
or

    fn func() 'a:{
would be better for indicating that 'a should outlive function execution.

Maybe some directional character would be better than : (> is probably out of question because of generics)

----

I feel like structs that don't have 'static lifetimes because they contain some borrows should have it indicated in their name.

For example:

    struct Handle& { n:&'a Node }
or even

    struct Handle&'a { n:&'a Node }
or

    struct Handle& 'a:{ n:&'a Node }
to indicate that 'a must outlive the struct.

Then you could use it:

    let h = Handle& { n: &some_node };
Maybe functions that create non-static struct might have & at the ends in their names.

Like

    vec![].into_iter().map()
but

    vec![].iter&().map()
    
You could easily see that you are dealing with something you should treat like a borrow because it contains borrows. Such structs would be sort of named, complex borrow and raw '&' borrow would be anonymous or naked borrow.

Not sure if it would also be nice to differentiate structs with &mut

----

I would just like to separate lifetimes syntax from generics syntax because those two things have nothing to do with each other from the point of view of the user of the language.

----

I would also like to have

while cond {} else {}

where else is only entered if cond was false from the start. But that's a wish not specific to Rust.

Re: Rust for Professionals

#74

Earlier quoted context omitted.

> It's not hard, Yep, that's the standard Rust aficionado flat insistence: "You're finding it hard. You're just wrong". Yet with more learning time than I've put into any other language I've learned, I have been unable to use Rust for real (ie. beyond beginner toys). A quick count of langs I've used professionally comes to about 10; I've learned many more to play with, much more successfully than with Rust, in much l…

Just to be clear, again, lots of people find rust difficult. I found it easy. Lots of people find it easy. That's interesting. Saying "rust is difficult" is silly to me because... it wasn't for me. Saying "rust is easy" is less silly to me because for me it was, but obviously for you it will be more silly because it isn't easy for you. You'll find that many in the rust community are in fact very very sympathetic to y…

> You'll find that many in the rust community are in fact very very sympathetic to your view that it's too hard to learn.

I have not found that. The very comment I'm responding to above is a correction, telling me "it's not hard", not saying on the writer's part that they didn't find it hard, and least of all with any curiosity towards any dev claiming that they find Rust hard, because that view is considered in the Rust commmunity plainly incorrect. This is what I have found, consistently in 2022. I plan to continue with Rust in 2023, but I'll probably largely go it alone.

Re: Rust for Professionals

#75
post #16

any constructive criticism on rust syntax?

With the caveat that syntax is the ultimate bikeshed topic, one (IMO) syntactic wart is the special pattern syntax: 1. "Operators" have different meanings. `1 | 2` and `1..=2` mean something different in patterns than in expressions. Here is a silly example: https://rust.godbolt.org/z/76Ynrs71G 2. Ambiguity around when bindings are introduced. Notice how changing a `const` to a `let` breaks the function: https://rust…

> 2.

This actually bit me in the a__ when I misspelled my enum variant and instead match created a variable named like that, that captured everything and I got only a warning and very wrong code.

I think there should be `let`s inside match block if matching creates some variables.

Re: Rust for Professionals

#76

Earlier quoted context omitted.

> In C++, move semantics are obvious because ... In Rust it's also obvious because every = is a move. Confusion comes from tutorials pretending for too long that it's not. > whereas in Rust, similar behavior seemed to depend on the object type. It's best to think of that as an exception to the rule created specifically for numbers and other similar small, cheaply copied things. If you need to move `a` but `a` has a t…

> In Rust it's also obvious because every = is a move. False, depending on the presence of an explicit type annotation on the left-hand side, an = triggers either a move or a reborrow.

How does it look like? Do you mean this? https://haibane-tenshi.github.io/rust-reborrowing/

If you assume = always moves you can just never use automatic reborrowing (do &mut * instead) and you'll loose nothing.

I don't think that's a very common pattern, fully optional and it can be just treated as another exception to the rule, just like Copy types. You don't have to manually write .copy() in some cases, and you don't have to manually write &mut* in some others. But that's what happens. Move is still done.

So that's total of two exceptions. Way easier to be tackled individually when the time comes than assuming = means something else, or something complex from the start.

Re: Rust for Professionals

#77

Earlier quoted context omitted.

> In C++, move semantics are obvious because ... In Rust it's also obvious because every = is a move. Confusion comes from tutorials pretending for too long that it's not. > whereas in Rust, similar behavior seemed to depend on the object type. It's best to think of that as an exception to the rule created specifically for numbers and other similar small, cheaply copied things. If you need to move `a` but `a` has a t…

> In Rust it's also obvious because every = is a move. False, depending on the presence of an explicit type annotation on the left-hand side, an = triggers either a move or a reborrow.

[deleted]

Re: Rust for Professionals

#78

Earlier quoted context omitted.

Because when you pass by reference, you lend the value (or to phrase it the other way around: the function borrows the value). And so when the function’s done, it gives you the value back (because that’s how borrowing works, in the everyday sense of the word, as well as in th Rust sense)

This is either wrong or incomplete. When you call a function `f()` with some `&mut`, the callee gets a `&mut`, not a borrowed `&mut &mut`. The callee doesn't borrow the ref mut, it gets the actual ref mut, and for some time you have multiple mutable references in the same scope. How?

It gets `&mut *&mut` (where * doesn't mean a pointer, just deref)

Not sure if that's good that this feature is automatic. Maybe it wouldn't be too bad to call functions like that for consistency:

    go_break_stuff(&mut *my_stuff_ref);
if you want to keep using the reference after the call.

Re: Rust for Professionals

#79

Earlier quoted context omitted.

> In Rust it's also obvious because every = is a move. False, depending on the presence of an explicit type annotation on the left-hand side, an = triggers either a move or a reborrow.

How does it look like? Do you mean this? https://haibane-tenshi.github.io/rust-reborrowing/ If you assume = always moves you can just never use automatic reborrowing (do &mut * instead) and you'll loose nothing. I don't think that's a very common pattern, fully optional and it can be just treated as another exception to the rule, just like Copy types. You don't have to manually write .copy() in some cases, and you do…

I've posted similar minimal examples before. The first one triggers a move (and then fails to compile), while the second one triggers a reborrow. Sure, you can explicitly write out every instance of reborrowing with `&mut *`. That would require you to understand every instance that triggers it, and would also be unbelievably noisy, since automatic dereferencing and automatic reborrowing are actually incredibly common.

  > pub fn main() {
  >     let mut x = String::from("moo");
  >     let y = &mut x;
  >     let z = y;
  >     println!("{:?}", y)
  > }
  > 
  > pub fn main() {
  >     let mut x = String::from("moo");
  >     let y = &mut x;
  >     let z: &mut _ = y;
  >     println!("{:?}", y)
  > }

Re: Rust for Professionals

#80

Earlier quoted context omitted.

> In Rust it's also obvious because every = is a move. False, depending on the presence of an explicit type annotation on the left-hand side, an = triggers either a move or a reborrow.

How does it look like? Do you mean this? https://haibane-tenshi.github.io/rust-reborrowing/ If you assume = always moves you can just never use automatic reborrowing (do &mut * instead) and you'll loose nothing. I don't think that's a very common pattern, fully optional and it can be just treated as another exception to the rule, just like Copy types. You don't have to manually write .copy() in some cases, and you do…

There's a way of thinking of `Copy` which makes it not an exception: `Copy` variables/places are simply not rendered invalid/uninitialized when they are the source of a move operation, unlike non-`Copy` sources. They're still moved from bitwise like all other rust values!
Post reply on HN