On 04/11/2011 5:32 AM, Marijn Haverbeke wrote:
Contrary to the old kinds, this forms a hierarchy, and the kinds lower in the list can be treated as sub-kinds of those above them (a 'send,copy' value can be safely treated as a 'nosend,nocopy' value).
The old scheme was a lattice as well. But I appreciate your motives here and the direction you're taking this. If you can make it hold together, I've no objection.
Try to tone down the negativity though? I had to hold of replying to this email longer than I wanted to due to stifling my emotional reaction to all the judgmental language ("not good", "awkward", "doesn't do", "actually work", "useless", etc.) I did *try* in the existing kind system, did the best I could, and it has caught a lot of bugs and helped enforce our memory model.
That said, I agree it's not ideal (counterintuitive in some places, ill-defined in others). It's just more productive to phrase things in terms of what is improved, which I see you're also doing. A few notes (mostly vigorous agreement):
Most generic functions will neither send nor copy values of their parameterized type, so they can safely default to 'nosend,nocopy' without losing genericity. When they *do* copy or send, and the programmer forgets to annotate the type parameter as such, a clear, understandable error message can be provided.
I think there's more copying than you expect, but "most" is something it's worth doing experiments on, certainly.
I like nocopy/nosend as a default though, because it encourages writing in move-centric style, which is often synonymous with "efficient code" style.
Generic types (type<T> and tag<T>) do not seem to have a reason to ever narrow their kind bounds in this system, so (unless I am missing something), they should probably not even be allowed to specify a kind on their parameters.
Agreed.
It might be useful to consider the last use of a local (let) variable to be an rvalue, since that local will never be referenced again, and it is always safe to move out of it. This will cause most returns to become moves (though returning a non-move-mode argument or the content of a data structure is still a copy).
Agreed. Returns should be considered move-outs.
Block safety will have to be handled on a more or less syntactic level. Values with block type can be restricted to only appear in function argument or callee position, and when appearing in argument position, the argument mode has to be by-reference. This is a kludge, but a relatively simple one (a small pass coming after typechecking can verify it).
This kludge is my only real concern, but if you can nail it down then go for it.
*) Resources that can't be moved are rather useless. They can only exist as local variables and never be stored in a data structure. This is why there is currently a kludge in the kind-checking code to allow resources to be constructed into data structures. This is needlessly special-cased, and doesn't really work very well at the moment (you can't, for example, put a resource in a tag value.)
The existing approach required us to differentiate "initialization" as a separate evaluation context from "existing rvalue". We did not fully implement this distinction, which is why there are such gaps in the existing scheme.
I agree that this scheme is counter-intuitive and if your proposed approach, by eliminating that distinction, may work better.
-Graydon _______________________________________________ Rust-dev mailing list [email protected] https://mail.mozilla.org/listinfo/rust-dev
