Hi Gareth,

Your recent e-mail reminded me that I never responded to this one. Sorry about that, I was on vacation.

There is one other way. You can restructure the caller. The most ambitious would be to change the field from mutable to immutable, but often that does not work. In that case, you can also update the type of the record from @{mut f: option<T>} to @{mut f: @option<T>}. You would then call the function with `*r.f` (where `r` is the record). This is permitted because, while the `f` field is mutable, the field does not store the option but rather a pointer to the option. The *option itself* is stored in immutable memory (that is, the @ box).

This makes sense. However I feel it encourages me to wrap all mutable record/class fields in @ boxes, which to me seems awkward to read/write and probably inefficient too.

I didn't mean to imply that this was a superior solution, merely that it was another solution. It is not always suitable but, in some cases, the @ boxes may already have been allocated, or the cost of allocation may be insignificant.

In general I think the most widely applicable answer is that if you want to put an enum into a mutable field, just make sure that it is cheaply copyable. So don't have `option<my_big_record>` but rather `option<@my_big_record>`. This is probably a good idea anyway, since you don't want to be copying big things around all the time.

Is there potential for the copy to be cheap enough to use `option<T>` (without the pointer)? I feel that by-copy is simpler to reason about and also easier to read/write.

I don't know what's best. We may want to have two functions/methods, one which expects a pointer and one which doesn't. The copy of an option<T> is not inherently expensive: its cost will naturally depend on T. Certainly we want a *option<T> variant for those cases where T is something prohibitively expensive to copy, such as a unique pointer, or where it has identity.

We may want both versions for other reasons. In the mode world, it is common to run up against mode mismatches: the function is declared with mode ++, for example, but is being used in a context where && is required. The equivalent in a region world would be a function that expects T being used in a context where *T is expected. It's also possible we could write a generic conversion wrapper to deal with this situation, something like:

    fn to_val<T,U>(f: fn(T) -> U, x: *T) -> U { f(*x) }



Niko
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to