[rust-dev] On Copy = POD

Benjamin Striegel ben.striegel at gmail.com
Sat Jun 21 09:05:55 PDT 2014

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

> 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
> _______________________________________________
> 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/47bebf5d/attachment.html>

More information about the Rust-dev mailing list