-
Notifications
You must be signed in to change notification settings - Fork 13.5k
impl Debug for Atomic types #27129
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
impl Debug for Atomic types #27129
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. The way Github handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
|
||
macro_rules! impl_Debug { | ||
($($t:ident)*) => ($( | ||
impl fmt::Debug for $t { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe these would need a stability attribute (#[stable(feature = "atomic_debug", since = "1.3.0")]
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trait impls are insta-stable, so it seems kinda useless...?
I feel like I've had this conversation a ton of times and keep forgetting why it might be useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other impls are still marked, though. Even if it's insta-stable having the version information of when an impl appeared can be useful for understanding the version requirements of your code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it though? Either you have a compiler that can build it, or you don't. I suppose if you have one that can build it, you can query if you can use an older one...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in order to determine the oldest Rust version I support, I should do I binary search on all Rust releases to determine which can build my project?
Seems fine to me, in terms of the impl existing. |
($($t:ident)*) => ($( | ||
impl fmt::Debug for $t { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
write!(f, "Atomic {{ {:?} }}", self.load(Ordering::Relaxed)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this should be write!(f, concat!(stringify!($t), "{{ {:?} }}", ...)
so as to actually print which type this is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These implementations should match the relevant RFC. I'm not sure if these should be treated like smart pointers, in which case this would just be self.load(Ordering::Relaxed).fmt(fmt)
, or a struct, in which case something like this should suffice:
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple(stringify!($t)).field(&self.load(Ordering::Relaxed)).finish()
}
Updated the commit. I tried to address all points raised in the comments. |
macro_rules! impl_Debug { | ||
($($t:ident)*) => ($( | ||
impl fmt::Debug for $t { | ||
#[stable(feature = "atomic_debug", since = "1.3.0")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These attributes go on the impl, not the method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, of course. Amending it right away
Why Relaxed rather than SeqCst? Seems like SeqCst should always be preferred unless there is a performance reason. |
#[stable(feature = "atomic_debug", since = "1.3.0")] | ||
impl<T: fmt::Debug> fmt::Debug for AtomicPtr<T> { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
f.debug_tuple(stringify!($t)).field(&self.load(Ordering::Relaxed)).finish() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks wrong. Especially the stringify!($t)
part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not inside a macro, therefore at least the $t
part is invalid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, I just realized this is the real impl :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duh, I gotta remind myself of these failures when I try to fast amend things
@arielb1 on hardware with a weak memory model, SeqCst would force synchronization between cores running this code and cores modifying the data, which is unnecessary since this code doesn't have synchronization requirements. It'd still be racy even with SeqCst (since by the time the value is formatted it could have changed) |
impl_Debug!{ AtomicUsize AtomicIsize AtomicBool } | ||
|
||
#[stable(feature = "atomic_debug", since = "1.3.0")] | ||
impl<T: fmt::Debug> fmt::Debug for AtomicPtr<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this doesn't need the bound on fmt::Debug
as that impl isn't used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Fixed.
We still have to figure out the default Ordering for it. I'm with @cmr on this one since even with strong ordering semantics there's no guarantee whatsoever that the underlining value didn't change after the load. |
|
@arielb1 what kind of trouble? |
Unpredictable results. If you do have some kind of synchronization, Relaxed-stores can still return a random-ish value. |
@arielb1 |
@arthurprs let's switch it to |
Commit updated to use SeqCst. |
I'm being constantly bitten by the lack of this implementation. I'm unsure if there's a reason to avoid these implementations though. Since we have a "lossy" implementation for both Mutex and RWLock (RWLock {{ locked }}) I don't think there's a big reason for not having a Debug implementation for the atomic types, even if the user can't specify the ordering.
I'm being constantly bitten by the lack of this implementation.
I'm unsure if there's a reason to avoid these implementations though.
Since we have a "lossy" implementation for both Mutex and RWLock (RWLock {{ locked }}) I don't think there's a big reason for not having a Debug implementation for the atomic types, even if the user can't specify the ordering.