4 ms·
Rust is not so different from Perl in this regard — there are many ways to do practically everything. Do you want an argument that implements a trait? Cool, jus
by chc 4y ago
Rust is not so different from Perl in this regard — there are many ways to do practically everything. Do you want an argument that implements a trait? Cool, just use a generic with a trait bound (either specified as `<T: Trait>` or `<T> where T: Trait`). Or type the argument as `impl Trait`. Or take a `Box<dyn Trait>`.
- a1369209993 4y agoI'm not particularly fluent in Rust, but at least several of those express meaningful differences in what you're doing, not just how. Eg are you promising to deallocate and otherwise clean up the object when you're done with it, versus are you promising that the caller can keep using it after you return.
- tialaramex 4y agoWhilst there are differences, that's not one of them. What decides whether the caller still has something is whether you passed it by reference. fn eat(food: Edible) just takes an actual Edible. Afterwards the food is gone, perhaps this function stashed it somewhere, or gave it away, but you don't have it any more† so maybe it was Dropped (destroyed) fn sniff(food: &Edible) -> Smell this time our function only wants an immutable reference to the Edible. The food isn't changed in any way by this predicate, it's still yours, and now you also know how it Smells. fn lick(food: &mut Edible) -> Review but this function modifies the Edible via the exclusive reference. You still have the food, and now you've got a Review, but the food may be changed, perhaps irreversibly by being licked. † If Edible is Copy then Rust will just copy it, so the caller still has it, types which are Copy are typically small, and they can't implement Drop, so if they were destroyed nothing happens anyway. An integer is Copy, a String isn't Copy, and neither is a File, or a network Socket, or whatever. You can make your own types Copy, if you want, and if they qualify.
- a1369209993 4y ago> What decides whether the caller still has something is whether you passed it by reference. I was referring to the `Box<dyn Trait>` one, as I'm at least 90% sure `Box<X>` passes a owned, dynamically-allocated X by reference (ie, Box<X> is a pointer to X).
- tialaramex 4y agoA Box<dyn Bird> is some sort of Bird on the heap. But if I pass a Box<Goose> to a function which wants a Box<dyn Bird>, then my call moves the Box<Goose> into the function, I don't still have that Goose, it's gone, I hope the function takes good care of it. If the function only wanted a reference to it, that would be &Box<dyn Bird> and then I wouldn't give up ownership by passing it to the function. But that's also a very strange thing to ask for, since we can instead pass a reference to a Bird, no need to Box it.
- a1369209993 4y ago> A Box<dyn Bird> is some sort of Bird on the heap. No, a Box<dyn Bird> is a pointer to some sort of Bird on the heap. Unless Rust has wildly changed how it implements function calls/stack frames, local variables are stored on the stack. A pointer is a reference to the thing it points to (in sense used in the phrase "pass by reference"). > then my call moves the Box<Goose> into the function, I don't still have that Goose Yes: you passed a Box<Goose> by value, you passed the Goose it points to by reference, and you transfered ownership of both.
- tialaramex 4y agoI think what got confused here is just the nomenclature? In particular the use of "reference" to mean what we get when we borrow something in Rust, and its use to mean the address of something as part of a calling convention. > are you promising to deallocate and otherwise clean up the object when you're done with it, versus are you promising that the caller can keep using it after you return. Whether I ask for a Goose or a Box<Goose>, it's mine now. The caller no longer has it, it's not just that they shouldn't use it, they can't, the compiler won't let them. Since it's mine, it is now my responsibility as owner either clean up, give it to somebody else or explicitly leak() it. Rust doesn't promise how exactly this is implemented, and it is likely to be different for an object of 4 bytes than for an object of 400 bytes.
- chc 4y agoNone of the snippets in my post indicate borrowing. You can borrow or not borrow any of the types above. It is true, though, that there are differences. With the generic, you can refer to the type again later, whereas the type is anonymous with `impl Trait`. And `dyn Trait` gives you dynamic dispatch. But in my experience there are usually some differences between the multiple ways to do something in Perk as well.