Remix.run Logo
kibwen 5 days ago

> In any language, when we hand a function a reference to an object, that function can't destroy the object, nor change its type

This isn't quite true. While Rust doesn't currently support this, people have proposed the concept of `&own` references that take ownership of the object and free it when the reference goes out of scope (consider that Rust's standard destructor signature, `fn drop(&mut)`, should probably take one of these hypothetical owning references). I addition, I believe that languages with typestate can cause types to change as a result of function calls, although I don't quite understand the details.

littlestymaar 4 days ago | parent | next [-]

Intriguing, what would be the purpose of such owning references compared to just passing ownership? Is that to have a way to reliably avoid memcopying large objects when passing them by value?

kibwen 4 days ago | parent [-]

> Is that to have a way to reliably avoid memcopying large objects when passing them by value?

I believe so, yes. Currently the only way to transfer ownership is by-value, and LLVM might optimize away the memcpy, but also it might not.

codedokode 4 days ago | parent [-]

I wonder what is the case when you cannot optimize away memcpy, but can work around it with an "owning reference"?

verdagon 5 days ago | parent | prev | next [-]

Great point =) That's true for a lot of languages (including Mojo too), so I should have said "non-owning reference" there. I'll update the post to clarify. Thanks for catching that!

skywal_l 5 days ago | parent | prev | next [-]

I don't understand your comment. `drop` takes a *mutable* reference. But by default, references in Rust are immutable.

littlestymaar 4 days ago | parent | next [-]

shared references are immutable in Rust, mut references and shared references are both references.

Ygg2 4 days ago | parent | prev | next [-]

Kibwen is saying that there was an idea to have `fn drop(&mut x)` from Drop trait become `fn drop_own(&own x)`. Then `&own` would do mutation and drop the owner of the reference. A regular &mut reference shouldn't do that outside of `drop(&mut x)`.

codedokode 4 days ago | parent | prev [-]

Drop takes an object itself ("owned reference"), as I remember. Mutable ref allows reading/writing but not destroying or passing the ownership.

Owner = can read/write/destroy

Mutable ref = can read/write

Immutable ref = can only read, guarantered not to change

steveklabnik 4 days ago | parent [-]

https://doc.rust-lang.org/stable/std/ops/trait.Drop.html#tym...

codedokode 4 days ago | parent [-]

That's the destructor function, that is written by you and called by Rust before actually destroying something. The function that you want to look at is [1].

If you read the docs at your link it even says:

> This method is called implicitly when the value goes out of scope, and cannot be called explicitly (this is compiler error E0040).

> However, the mem::drop function in the prelude can be used to call the argument’s Drop implementation.

By the way the implementation of the function drop is just an empty function [2]; that's enough as local variables are destroyed on function return.

Mutable reference is a "borrow" which means you take a value from an owner and promise to return it back, and you cannot destroy a thing that you must return.

[1] https://doc.rust-lang.org/std/mem/fn.drop.html

[2] https://doc.rust-lang.org/src/core/mem/mod.rs.html#957

steveklabnik 4 days ago | parent [-]

The drop function being talked about here is the one I pointed to, not the one you pointed to. The Drop trait is built into the language (as a lang item), std::mem::drop is just a regular old function.

codedokode 4 days ago | parent [-]

The drop that you mention doesn't free memory, as I understand, it is called before actually destroying object's memory.

steveklabnik 4 days ago | parent [-]

Not inherently, sure. But ultimately this is far afield of what I was trying to say, which is that the signature being discussed of being changed from &mut T to &owned T is the one from the Drop trait. That’s it.

modulared 4 days ago | parent | prev | next [-]

> I believe that languages with typestate can cause types to change as a result of function calls

Do you have any specific languages?

kibwen 3 days ago | parent [-]

I've only heard of this concept in academic languages, I don't feel knowledgeable enough to recommend any specific one. In terms of mainstream languages, I think an analogous concept is the use-before-initialization analysis that languages like Rust employ, e.g. if I have a variable defined like this:

    let x: u8;
I can't actually do anything with this variable:

    foo(x); // error
Except I can apply the initialization operator:

    x = 42;
And now I can do things with this variable as usual.

But consider that the type of x hasn't changed as a result of the initialization. Beforehand it was a u8, and afterward it was still a u8, and yet something about the state of the variable changed my ability to use it in various contexts. I believe that typestate is something like this, generalized to allow variables to flow through states (like a compile-time state machine) to ensure that things happen in the correct order.

wavemode 4 days ago | parent | prev [-]

An &own reference seems like it would just be equivalent to a Box.

steveklabnik 4 days ago | parent [-]

Box heap allocates, references do not.

wavemode 4 days ago | parent [-]

> `&own` references that take ownership of the object and free it when the reference goes out of scope

How can you free something if it's not allocated

steveklabnik 4 days ago | parent [-]

Sorry, yeah that phrasing was bad: I kinda think an "owning reference" is a contradiction in terms but I didn't come up with the idea.

What I meant was, creating a box creates a new allocation, whereas my understanding of &own would take over an existing allocation.