# Thoughts on `AtomicU32` method calls ## The problem We would like to be able to call an `atomic_add` method on [`AtomicU32`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicU32.html). ## Options before arbitrary self types ```rust AtomicU32::atomic_add(addr_of!(self.field), 1) ``` (not a fn that exists today) where `atomic_add` is a new fn with a signature like ```rust fn atomic_add(p: *const AtomicU32, amount: usize) ``` ## With the current simplest arbitrary self types proposal Currently, the simplest proposal for arbitrary self types does not allow method calls on raw pointers. ## With more complex arbitrary self type proposals More complex options for arbitrary self types would allow: ```rust impl AtomicU32 { fn atomic_add(self: *const Self, amount: usize) { } } ``` and calls like: ```rust addr_of!(self.field).atomic_add(1) ``` ## Other alternatives ### `act_on_addr!` macro ```rust act_on_addr!(self.field, atomic_add(1)) ``` which expands to ```rust AtomicU32::atomic_add(addr_of!(self.field), 1) ``` ### `call_on_addr!` macro The same, but more like a method call (would probably need to be a proc macro) ```rust call_on_addr!(self.field.atomic_add(1)) ``` Expands to the same thing, even though `atomic_add` is not a method. ### Newtype wrapper for raw pointers It's been proposed that we have: ```rust struct Raw<T>(*const T); // impls Receiver ``` so that methods could be expressed as: ```rust impl AtomicU32 { fn atomic_add(self: &Raw<Self>, amount: usize) { } } ``` Personally I don't like this. It feels to me like we're (likely) avoiding adding method on `*const T` because we're worried about shadowing methods on `T`; the same problem would prevent us adding methods on `Raw<T>` in future. But... if we decided to do this it would work like this: ```rust Raw(addr_of!(self.field)).atomic_add(1) // or addr_of!(self.field).as_raw().atomic_add(1) // or even addr_of!(self.field).into().atomic_add(1) ``` ### `CoerceFromPointer` trait Maybe `Raw<T>` implements a new trait which provides automatic coercion from `*const T`: ```rust addr_of!(self.field).atomic_add(1) ``` I can't see a way to do this without all the same old shadowing concerns, but putting it here for thought. ### Change method precedence (references, values, etc.) We sort of have a 2D grid of method order lookup right now. For `A<B<C>>` this is the order: | | by value | by reference | by mut reference | by ptr | |---|---|---|---|----| | A | 1 | 4 | 7 | 10 | | B | 2 | 5 | 8 | 11 | | C | 3 | 6 | 9 | 12 | In the more complex variants of the arbitrary self types proposal, we talked about sometimes altering the vertical order in the table above. But maybe we could alter the horizontal order: | | by ptr | by value | by reference | by mut reference | |---|---|---|---|----| | A | 1 | 4 | 7 | 10 | | B | 2 | 5 | 8 | 11 | | C | 3 | 6 | 9 | 12 | So, if a type yielded a `*const T` by following its deref chain, we would pick that method instead of any method on the outer type. I don't know if this would work. But it might be an alternative way for us to allow methods with raw pointer receivers in future. Or perhaps there's a way to do this together with the `CoerceFromPointer` trait. ### All new syntax `addr_of!` seems a bit weird because syntactically it looks like it's creating a reference. Maybe we need a `->` operator. This could either be used as direct syntactic sugar for `addr_of!`: ```rust let ptr = self->field; ``` or maybe it could be used for method calls: ```rust self.field->atomic_add(1) ``` by virtue of some new trait, e.g. `CoerceFromPointer` as suggested above, and a method like: ```rust impl AtomicU32 { fn atomic_add(self: &Raw<Self>, amount: usize) { } } ```