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