3 ms·
Can you give examples of the calls for these procedures? Because in my experience when I pass a value (not a reference), then I must borrow the value and cannot
by zelphirkalt 1y ago
Can you give examples of the calls for these procedures? Because in my experience when I pass a value (not a reference), then I must borrow the value and cannot use it later in the calling procedure. Passing a reference of course is something different. That comes with its own additional syntax that is needed for when you want to do something with the thing that is referred to.
- Tuna-Fish 1y ago> Because in my experience when I pass a value (not a reference), then I must borrow the value and cannot use it later in the calling procedure. Ah, you are confused on terminology. Borrowing is a thing that only happens when you make references. What you are doing when you pass a non-copy value is moving it. Generally, anything that is not copy you pass to a function should be a (non-mut) reference unless it's specifically needed to be something else. This allows you to borrow it in the callee, which means the caller gets it back after the call. That's the workflow that the type system works best with, thanks to autoref having all your functions use borrowed values is the most convenient way to write code. Note that when you pass a value type to a function, in Rust that is always a copy. For non-copy types, that just means move semantics meaning you also must stop using it at the call site. You should not deal with this in general by calling clone on everything, but instead should derive copy on the types for which it makes sense (small, value semantics), and use borrowed references for the rest.
- zelphirkalt 1y agoIt is not possible then to pass a value (not a reference) and not implement or derive Copy or Clone, if I understand you correctly. That was my impression earlier. Other languages let you pass a value, and I just don't mutate that, if I can help it. I usually don't want to pass a reference, as that involves syntactical "work" when wanting to use the referenced thing in the callee. In many other languages I get that at no syntactical cost. I pass the thing by its name and I can use it in the callee and in the caller after the call. What I would prefer is, that Rust only cares about whether I use it in the caller after the call, if I pass a mutable value, because in that case, of course it could be unsafe, if the callee mutates it. Sometimes Copy cannot be derived and then one needs to implement it or Clone. A few months ago I used Rust again for a short duration, and I had that case. If I recall correctly it was some Serde struct and Copy could not be derived, because the struct had a String or &str inside it. That should a be fairly common case.
- steveklabnik 1y agoYes, Rust will not automatically turn a value into a reference for you. A reference is the semantic you desire. If you have a value, you’re gonna have to toss & on it. That’s the idiomatic way to do this, not to pass a value and clone it. &str is Copy, String is not.
- Tuna-Fish 1y agoYou can pass a value that is neither copy or clone, but then it gets moved into the callee, and is no longer available in the caller. Note that calling by value is expensive for large types. What those other languages do is just always call by reference, which you seem to confuse for calling by value. Rust can certainly not do what you would prefer. In order to typecheck a function, Rust only needs the code of that function, and the type defitions of everything else, the contents of the functions don't matter. This is a very good rule, which makes code much easier to read.
- akkad33 1y agoIs it expensive in Rust? Normally only data in stack gets copied. Heap data is untouched
- Tuna-Fish 1y agoYes, but if you have a large value type it will be on the stack unless you manually box it. Passing by value can get quite expensive quite fast, especially if the value keeps being passed up and down the call chain.
- vlovich123 1y agoIf all you're doing is immutable access, you are perfectly free to immutably borrow the value as many times as you want (even in a multithreaded environment provided T is Send): let v = SomeValue { ... } foo(&v); foo(&v); eprintln!("{}", v.xyz); You have to take a reference. I'm not sure how you'd like to represent "I pass a non-reference value to a function but still retain ownership without copying" - like what if foo stored the value somewhere? Without a clone/copy to give an isolated instance, you've potentially now got two owners - foo and the caller of foo which isn't legal as ownership is strictly unique. If F# lets you do this, it's likely only because it's generating an implicit copy for you (which Rust is will do transparently for you when you declare your type inheriting Copy). But otherwise I'm not clear what ownership semantics you're trying to express - would be helpful if you could give an example.