[rust-dev] On Copy = POD
Paulo Sérgio Almeida
pssalmeida at gmail.com
Sun Jun 22 13:21:51 PDT 2014
Yes, but many users won't even attempt to write their own pointer types,
and will reap benefits from having nice support for the essential pointers,
that they can think of as built-in. Those that attempt to write their own
will not be in a worse position than they are now.
On 21 June 2014 17:05, Benjamin Striegel <ben.striegel at gmail.com> wrote:
> > A user won't care if Arc and Rc are built-in or not.
> They will definitely care, once they attempt to write their own pointer
> types and find that they're second-class citizens compared to the types
> that have been blessed by the compiler. There's little point in having a
> powerful and extensible language if even simple types need hardcoded
> compiler magic to function.
> On Sat, Jun 21, 2014 at 7:42 AM, Paulo Sérgio Almeida <
> pssalmeida at gmail.com> wrote:
>> Regarding the white-listing, I also find it weird, but should the user
>> experience be worse just because Rc and Arc are implemented in Rust and so
>> we should do nothing in the name of orthogonality? A user won't care if Arc
>> and Rc are built-in or not.
>> I may have passed the message that its only ugliness involved, and being
>> lazy to type .clone(). But the point is uniformity and coherence of the
>> pointers API, clarity, and ease of refactoring code. I am thinking of
>> writing an RFC about cleaning up pointers. As of now there are some, in my
>> opinion, needless non-uniformities in the use of pointers. I would like to
>> have some properties:
>> 1) Two programs that use pointers, identical except for pointer types and
>> that both compile should produce semantically equivalent result (i.e., only
>> differ in performance).
>> The idea is that different pointer types would be chosen according to
>> capabilities (is move enough or do I want to mutate something I own, pick
>> Box; do I want to share intra-task, pick Rc or Gc; inter-task, pick Arc).
>> If a program fragment is written using, say Gc, and later I decide to
>> switch to Rc, I should need only change the declaration site(s) and not
>> have to go all-over and add .clone().
>> (There are other things than Copy that need to be improved, like
>> uniformity of auto-dereferencing and auto-borrowing. Fortunately I hope
>> those to be not as controverse.)
>> 2) Pointers should be transparent, and avoid confusion between methods of
>> the pointer and methods of the referent.
>> In particular, having non Box pointers Copy and avoiding pointer cloning,
>> all .clone() in code would mean cloning the referent, being uniform with
>> what happens with Box pointers. A clone should be something more rare and
>> conscious. As of now, having mechanical .clone() in many places makes the
>> "real" refent clones less obvious. An unintended referent clone may go more
>> easily unnoticed.
>> (Other aspects involve switching to UFCS style for pointer methods.)
>> 3) Last use move optimisation should be applied for pointer types.
>> This is not as essential, but as now, the compiler will know the last use
>> place of a variable and use move instead of copy. All white-listed for Copy
>> pointer-types must allow this optimisation. As we are talking about a
>> controlled, to be approved set of types (i.e. Rc and Arc), and not general
>> user-defined types, we can be sure that for all white-listed types this is
>> so. Last use move optimisation would result in the same performance of code
>> as now. Again, this is coherent with Box types, where the first use (by
>> value) must be also the last use.
>> Anyway, I would like to stress that much fewer pointer copies will exist
>> in Rust given (auto-)borrowing. It is important to educate programers to
>> always start by considering &T in function arguments, if they only need to
>> use the T, and add more capabilities if needed. Something like &Rc<T> if
>> the function needs to use the T and occasionally copy the pointer, and only
>> Rc<T> if the normal case is copying the pointer.
>> This is why I even argue that Arc should be Copy even considering the
>> much more expensive copy. The important thing is programers knowing the
>> cost, which will happen for the very few white-listed types, as opposed to
>> allowing general user-defined copies for which the cost is not clear for
>> the reader. A program using Arc should not Use Arc all-over, but only in a
>> few places; after spawning, the proc will typically pass not the Arc<T> but
>> only &T to functions performing the work; this is unless those functions
>> need to spawn further tasks but in this case, the Arc copies are need and
>> in those places we would use .clone() anyway, resulting in the same
>> On 21 June 2014 10:10, Nick Cameron <lists at ncameron.org> wrote:
>>> I guess I forgot that C++ ref counted pointers (pre-11) generally have a
>>> move version of the type. Thanks for pointing that out.
>>> I agree it would be odd to copy that design (Rc/RcTemp) in a language
>>> which has move semantics by default. I wonder if we could come up with
>>> _some_ design that would be better than the current one. My reasoning is
>>> that copy-with-increment is the (overwhelmingly) common case for
>>> ref-counted pointers and so should be easier/prettier than the less common
>>> case (moving). One could argue that the more efficient case (moving) should
>>> be prettier and I think that is valid. I'm not sure how to square the two
>>> arguments. I do think this deserves more thought than just accepting the
>>> current (`.clone()`) situation - I think it is very un-ergonimic. Having
>>> two types rather than two copying mechanisms seems more preferable to me,
>>> but I hope there is a better solution.
>>> On Sat, Jun 21, 2014 at 6:21 PM, Cameron Zwarich <zwarich at mozilla.com>
>>>> On Jun 20, 2014, at 11:06 PM, Nick Cameron <lists at ncameron.org> wrote:
>>>> > zwarich: I haven't thought this through to a great extent, and I
>>>> don't think here is the right place to plan the API. But, you ought to
>>>> still have control over whether an Rc pointer is copied or referenced. If
>>>> you have an Rc<T> object and pass it to a function which takes an Rc<T>, it
>>>> is copied, if it takes a &Rc<T> or a &T then it references (in the latter
>>>> case with an autoderef-ref). If the function is parametric over U and takes
>>>> a &U, then we instantiate U with either Rc<T> or T (in either case it would
>>>> be passed by ref without an increment, deciding which is not changed by
>>>> having a copy constructor). If the function takes a U literal, then U must
>>>> be instantiated with Rc<T>. So, you still get to control whether you
>>>> reference with an increment or not.
>>>> > I think if Rc is copy, then it is always copied. I would not expect
>>>> it to ever move. I don't think that is untenable, performance wise, after
>>>> all it is what everyone is currently doing in C++. I agree the second
>>>> option seems unpredictable and thus less pleasant.
>>>> Copying on every single transfer of a ref-counted smart pointer is
>>>> definitely *not* what everyone is doing in C++. In C++11, move constructors
>>>> were added, partially to enable smart pointers to behave sanely and
>>>> eliminate extra copies in this fashion (albeit in some cases requiring
>>>> explicit moves rather than implicit ones like in Rust).
>>>> Before that, it was possible to encode this idiom using a separate
>>>> smart pointer for the expiring value. WebKit relies on (or relied on,
>>>> before C++11) a scheme like this for adequate performance:
>>>> In theory, you could encode such a scheme into this “always copy on
>>>> clone" version of Rust, where Rc would always copy, and RcTemp wouldn’t
>>>> even implement clone, and would only be moveable and convertible back to an
>>>> Rc. However, it seems strange to go out of your way to encode a bad version
>>>> of move semantics back into a language that has native move semantics.
>>> Rust-dev mailing list
>>> Rust-dev at mozilla.org
>> Rust-dev mailing list
>> Rust-dev at mozilla.org
> Rust-dev mailing list
> Rust-dev at mozilla.org
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Rust-dev