Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Rename Share to Sync #123

Merged
merged 3 commits into from
Aug 5, 2014

Conversation

alexcrichton
Copy link
Member

@alexcrichton alexcrichton commented Jun 16, 2014

@alexcrichton
Copy link
Member Author

cc rust-lang/rust#14828

@schmee
Copy link

schmee commented Jun 16, 2014

Allow me to commence the bikeshedding: I propose the name Sync. It's short, sweet, understandable and lines up nicely alongside Copy, Send and Sized.

@bstrie
Copy link
Contributor

bstrie commented Jun 17, 2014

Sync or Synchronized would seem to imply the existence of a runtime overhead where there is none.

@ftxqxd
Copy link
Contributor

ftxqxd commented Jun 17, 2014

Most of the time, ‘thread-safe’ is written with a hyphen or a space, and so should be counted as two words. That would make this trait ThreadSafe (although I do still prefer Threadsafe).

I personally don’t like the name Threadsafe at all—while it’s descriptive, it doesn’t fit together with the other built-in traits very well (Share, Copy, and Send are short common verbs, while Threadsafe is a long compound adjective). I think that although a renaming probably is necessary, Threadsafe is not the best option.

Another option would be to just use the word ‘aliasable’ to refer to &-pointers instead of ‘shared’. This means that Share can stay as-is, and the term ‘aliasable’ is already used quite a lot for that meaning.

@schmee Sync isn’t too bad a name—it’s short, it can be a verb, and it conveys its meaning fairly well (but @bstrie’s point is certainly valid).

@liigo
Copy link
Contributor

liigo commented Jun 17, 2014

Sync +1

@Valloric
Copy link

You can't call it Threadsafe when race conditions are still possible. People will laugh Rust out of the room.

@alexcrichton
Copy link
Member Author

I like the succinctness of Sync, but I'm not sure that it quite accurately conveys what the type is resilient too.

When I think of "sync" I think of "synchronized" which often refers to blocking threads or coordinating to wait for an event to happen. This trait implies that a type is sharable among many threads which at its bare minimum means that appropriate atomic operations are used. These two concepts seem similar, but distinct.

For example, I would not think of an AtomicUint as Sync due to it lacking any form of synchronization beyond atomic updates, but I would naturally consider it Threadsafe.

That being said, I think the drawbacks of Sync are similar to the drawbacks of Threadsafe, and there's no clear winner to me between those two.

@schmee
Copy link

schmee commented Jun 18, 2014

Based on your arguments above, I think that Atom is a great alternative. It has the same advantages that I mentioned for Sync, but it is more consistent with the actual semantics. You can share an Atom since it is indivisible. A RefCell can't be an Atom since you can look inside it and mutate its parts.

EDIT: this also has a nice likeness with atoms in Clojure, which are used to "...provide a way to manage shared, synchronous, independent state".

@bill-myers
Copy link

Threadsafe and Thread have the issue that they would become the most prominent use of the word "thread", which is otherwise not used much since Rust is based on tasks, and they are slightly wrong since the issue is task-safety and not thread-safety (although they are usually equivalent).

"Tasksafe" would fix that, but is not a widely used term.

Atomic is problematic since it usually implies that atomic CPU instructions or similar mechanisms are being used.

Atom is problematic since it is usually either a synonym of Atomic or refers to an interned string type, or to terminal symbols in parsing, or in general to an immutable primitive-valued constant.

Sync and Synchronized are problematic because they usually imply that a synchronization primitive is being used.

Parallel is problematic because it usually implies that the compiler or library is making some effort to parallelize computation using the type, or that the type is a parallelizable variant of a data structure available in non-parallelizable versions too.

DataRaceFree is multi-word and vague.

ConcurrentlySharable is too long.

This leaves Concurrent (a bit long, maybe a bit vague), Share (a bit vague), Threadsafe (slightly incorrect and a bit long) or Tasksafe (unusual).

@bstrie
Copy link
Contributor

bstrie commented Jun 18, 2014

Concurrent isn't terrible. How often would you need to type it?

@liigo
Copy link
Contributor

liigo commented Jun 18, 2014

Perhaps rename share is a mistake?
2014年6月19日 上午4:10于 "bill-myers" notifications@github.com写道:

Threadsafe and Thread have the issue that they would become the most
prominent use of the word "thread", which is otherwise not used much since
Rust is based on tasks, and they are slightly wrong since the issue is
task-safety and not thread-safety (although they are usually equivalent).

"Tasksafe" would fix that, but is not a widely used term.

Atomic is problematic since it usually implies that atomic CPU
instructions or similar mechanisms are being used.

Atom is problematic since it is usually either a synonym of Atomic or
refers to an interned string type, or to terminal symbols in parsing, or in
general to an immutable primitive-valued constant.

Sync and Synchronized are problematic because they usually imply that a
synchronization primitive is being used.

Parallel is problematic because it usually implies that the compiler or
library is making some effort to parallelize computation using the type, or
that the type is a parallelizable variant of a data structure available in
non-parallelizable versions too.

DataRaceFree is multi-word and vague.

ConcurrentlySharable is too long.

This leaves Concurrent (a bit long, maybe a bit vague), Share (a bit
vague), Threadsafe (slightly incorrect and a bit long) or Tasksafe
(unusual).


Reply to this email directly or view it on GitHub
#123 (comment).

@aturon
Copy link
Member

aturon commented Jun 19, 2014

+1 for Concurrent or Sync

@DaGenix
Copy link

DaGenix commented Jun 19, 2014

I like Threadsafe and Concurrent. I don't like the other alternatives since they all seem to imply specific implementations.

@glaebhoerl
Copy link
Contributor

EDIT: I made a dumb comment. It is below for reference. Don't read it.

I question the premise:

With interior mutability, the name "immutable pointer" for a value of type &T is not quite accurate. Instead, the term "shared reference" is becoming popular to reference values of type &T. The usage of the term "shared" is in conflict with the Share trait, which is intended for types which can be safely shared concurrently with a shared reference.

"Shared references may be formed to immutables values or to types which implement Share."

That sounds completely fine to me, and more like valuable intuition-building than a conflict.

@dobkeratops
Copy link

I'm told 'Share' is a bound I would need for closures that are safe for data-parallel iterators.
"how often would you have to write it" is "as often as possible" for code thats' parallelizable (e.g. multicore game engine)

I very much hope immutable closures are a case that can be expressed after closure reform - since immutable means its' threadsafe aswell - but also makes inputs / outputs / side-effects clearer. (immutable is suitable for the data-parallel case, and communicates more information about what code does & doesn't do)

@NawfelBgh
Copy link

+1 for Share

@anasazi
Copy link

anasazi commented Jun 30, 2014

What about using DRF as a shorter form of DataRaceFree?

@flaper87
Copy link

For the sake of bikeshedding, I'd prefer to keep built-in traits a 1-word long. I think Synchronized might work, although I'd still prefer to keep Share and have it well documented despite the issues mentioned in this RFC w.r.t to documenting &T

@alexcrichton
Copy link
Member Author

As discussed in today's meeting I have updated the name to Sync instead of Threadsafe

@netvl
Copy link

netvl commented Jul 23, 2014

At first I thought that Sync is absolutely not appropriate exactly for the reason listed in "Drawbacks" section because synchronization means some explicit action, like taking over a mutex; but according to current Share documentation, this is absolutely not always the case:

The precise definition is: a type T is Share if &T is thread-safe. In other words, there is no possibility of data races when passing &T references between tasks.

As one would expect, primitive types like u8 and f64 are all Share, and so are simple aggregate types containing them (like tuples, structs and enums). More instances of basic Share types include "immutable" types like &T and those with simple inherited mutability, such as Box, Vec and most other collection types. (Generic parameters need to be Share for their container to be Share.)

However, I don't understand why the documentation states that "there is no possibility of data races when passing &T references between tasks", that is, how it is possible to pass any reference between tasks at all? As far as I understand (and I tripped over this several times) no reference other than &'static can be passed between tasks because the referenced value still lives in the original task, and when that original task terminates, there is a possibility for a dangling pointer in the other task. This is prevented by the compiler now (because &T is not Send), but the documentation on Share suggests otherwise. Or maybe I'm misunderstanding what it says?

Probably if the documentation on Share is reworded (or at least its actual meaning is explained somewhere, e.g. in this RFC, until the documentation is fixed), it will be more understandable why Share should become Sync.

@huonw
Copy link
Member

huonw commented Jul 23, 2014

There's no safe way to pass &T between tasks spawned with std::task::spawn, but, if you do do it with unsafe (while ensuring that the aliasing/validity rules are obeyed), then you won't be subject to data races as long as T: Share.

This behaviour is designed to allow fork-join/data-parallelism libraries to expose safe and performant interfaces (even if they have to use unsafe internally), e.g.

/// call `func` on each element of `data` in its own task, blocking until 
/// all tasks complete.
fn par_apply<T: Share>(data: &[T], func: fn(&T)) {
    // (raw function pointer until the nicer closures work)
    unsafe { ... }
}

This function is safe because each &T is guaranteed to be valid for the whole par_apply call, and the par_apply function doesn't return until every task has finished. This ensures that each task's &T is always valid, and the Share ensures freedom from data-races/memory-unsafety.

@netvl
Copy link

netvl commented Jul 23, 2014

So Share is only useful in unsafe context, right? Then its renaming to Sync has even less sense. T: Share itself has nothing to do with synchronization; it is the outer code which uses it must synchronize tasks somehow. I guess Threadsafe is much more appropriate then.

@huonw
Copy link
Member

huonw commented Jul 23, 2014

So Share is only useful in unsafe context, right?

Share and Send are both only useful for exposing safe APIs relating to parallelism/concurrency, whether or not those APIs internally use unsafe doesn't matter from the outside.

T: Share itself has nothing to do with synchronization

Share essentially represents types where all read/writes via &T are internally synchronised, i.e. no race conditions between non-atomic variables. (This includes when it is vacuously true, i.e. situations like T = int where you can't write via &T.)

it is the outer code which uses it must synchronize tasks somehow

No, that's not what Share is. If you want to pass &Ts directly between tasks, then yes, you need to be ensuring the & lasts long enough, but (a) a &Mutex<T> is doing synchronisation internally to ensure thread-safety, and (b) Share is also required for Arc<T> to expose a safe interface.

That is, the Share kind is expressing a property about the type T (that shared access to it is threadsafe), it's not really talking about the nitty-gritty details of actually obtaining the &Ts in different tasks. The docs could be tweaked to remove the word 'passing', to reduce confusion.

(Just to be clear, I'm not arguing in favour of any name, just clearing misconceptions.)

@netvl
Copy link

netvl commented Jul 23, 2014

Thanks for thorough explanation. The situation you're describing is not really obvious from Share documentation. Well, I guess that'll change soon :)

Share and Send are both only useful for exposing safe APIs relating to parallelism/concurrency, whether or not those APIs internally use unsafe doesn't matter from the outside.

I was speaking from implementation's point of view, of course, that is, I meant that it is possible to actually use Share bound guarantees in unsafe context only, apart from trivial cases.

Share essentially represents types where all read/writes via &T are internally synchronised, i.e. no race conditions between non-atomic variables. (This includes when it is vacuously true, i.e. situations like T = int where you can't write via &T.)

Yeah, I probably should have expressed myself better. What I meant is that Share does not always mean underlying synchronization. Your example with parallel apply is probably the best example for this point. I'm not sure if these uses of Share are the major part of all its uses, though, but still the argument holds.

@Tobba
Copy link

Tobba commented Jul 30, 2014

In my opinion Concurrent is the most suitable name, Sync is a bit too short and implies that the object is actually synchronized, which it doesn't necessarily have to be to be safe

@nikomatsakis nikomatsakis merged commit 1484eb4 into rust-lang:master Aug 5, 2014
pnkfelix added a commit to pnkfelix/rfcs that referenced this pull request Oct 8, 2014
In particular:

* The RFC associated with rust-lang#127 should have had a link to rust-lang#19 as well
  (and has been assigned RFC rust-lang#19); it also was revised to match the
  markdown href style of other RFCs.

* RFC rust-lang#34 needed its header entries filled in,

* RFC rust-lang#123 had a typo in its header, and

* RC rust-lang#155 was revised to match the markdown href style of other RFCs.
@Centril Centril added A-convention Proposals relating to documentation conventions. A-sync Synchronization related proposals & ideas labels Nov 23, 2018
@dtolnay dtolnay changed the title RFC: Rename Share to Threadsafe RFC: Rename Share to Sync Jun 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-convention Proposals relating to documentation conventions. A-sync Synchronization related proposals & ideas
Projects
None yet
Development

Successfully merging this pull request may close these issues.