[rust-dev] On Copy = POD

Paulo Sérgio Almeida pssalmeida at gmail.com
Sat Jun 21 04:42:56 PDT 2014


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
performance.



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>
> wrote:
>
>> 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:
>>
>> https://www.webkit.org/coding/RefPtr.html
>>
>> 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.
>>
>> Cameron
>
>
>
> _______________________________________________
> Rust-dev mailing list
> Rust-dev at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140621/666ba914/attachment.html>


More information about the Rust-dev mailing list