I found in the library reference for std::rc::Rc this trait implementation
impl<T> !Send for Rc<T>
where
T: ?Sized,
What does the exclamation point in front of Send mean?
I consulted both The Rust Programming Language¹ book and The Rust Reference², but didn't find an explanation. Please give a reference in your answer.
¹ especially the [section 3.19 Traits
² and sections 5.1 Traits and 5.1 Implementations
It's a negative trait implementation for the Send trait as described in RFC 19.
As a summary: The Send trait is an auto trait, which means it is automatically implemented for all types that only contain other Send types:
unsafe auto trait Send {}
(Send is also an unsafe trait, which means it is unsafe to implement, but that is not relevant to the question.)
An auto trait may not define any methods, which also makes it a marker trait. (The syntax for defining auto traits is currently only available in the standard library or on the nightly compiler, but their semantics are stable.)
To opt out of the automatic implementation of Send, you must write an explicit negative trait implementation:
impl !Send for MyType {}
This means that even though MyType only contains other types that are Send, MyType itself will not automatically implement Send.
See also the answer to another question: What is an auto trait in Rust?
This is a negative trait impl, so you can read it as opting out of the Send trait.
From reference about auto traits:
Auto traits can also have negative implementations, shown as impl !AutoTrait for T in the standard library documentation, that override the automatic implementations. For example *mut T has a negative implementation of Send, and so *mut T is not Send, even if T is.
Related
While playing around with Rust and its generics I came along some problem for which I cannot find any documentation.
I have implemented a type Wrapper which wraps another type. At some point I wanted to implement the From trait.
impl<TSrc, TDst> From<Wrapper<TSrc>> for Wrapper<TDst>
where
TSrc: From<TDst>
{
fn from(other: Wrapper<TSrc>) -> Self {
todo!()
}
}
rustc complains with following error
58 | impl<TSrc, TDst> From<Wrapper<TSrc>> for Wrapper<TDst>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T> From<T> for T;
This makes sense if TSrc and TDst are the same. Is it somehow possible to explicitly exclude TSrc from TDst?
No, it is not possible to exclude specific types in a generic implementation.
There's not really a general workaround beyond "do something else" which would typically look like an inherent conversion method, using a different (custom) trait, or allowing another mechanism for users to access the inner values and do the conversion themselves.
There may be mechanisms in the future like specialization or negative impls that could allow such an implementation (or similar), but nothing is on the horizon.
See also:
How is there a conflicting implementation of `From` when using a generic type?
Why do blanket implementations for two different traits conflict?
Is it possible to exclude a type from generic trait implementation?
When looking through the documentation of Rust structs, I often come across a section with the title "Blanket Implementations". I have heard that it can be used to implement a trait for all types or all types that match some condition but I am not sure why this is needed.
So what really are Blanket Implementations and why are they useful in Rust?
A blanket implementation is an implementation of a trait on a generic parameter:
impl<T> Trait for T
They usually also have where clauses involved since it is very hard to do anything useful to an unconstrained T. This does not cover things like impl<T> Trait for Vec<T>, which is a generic implementation but not a blanket implementation.
They are documented separately since they are applied without any particularity and may or may not be relevant to the type you're looking at. Whereas for the normal "Trait Implementations" section, all those traits at least had some thought for the specific type in mind (usually).
They are patently useful since it implements the trait for anything, in the entire ecosystem! If something satisfies the constraints, then it is able to take advantage of the implementation without needing to implement it themselves. You do not need to do anything to "opt-in" besides bringing the trait into scope.
Some notable ones:
From<T> is implemented for all T (the identity implementation)
Into<U> is implemented for all T where T: From<U> (the reflexive implementation that allows you to call .into() when a matching From implementation exists)
Any is implemented for all T where T: 'static
They are also needed to implement "trait aliases" where you create a trait that is constrained over multiple other traits (handy for reducing boilerplate and needed for multi-trait trait objects). You use a blanket implementation that the trait is implemented for any type satisfying the super-traits:
trait MyCoolAsyncTrait: AsyncRead + AsyncWrite + AsyncSeek + 'static {}
impl<T> MyCoolAsyncTrait for T
where
T: AsyncRead + AsyncWrite + AsyncSeek + 'static
{ }
Be careful when adding them to your types though. Because of their extensive scope, they can easily conflict with other trait implementations that may be desirable. You can only define one blanket implementation per type (even if the constraints are non-overlapping).
See also:
What are blanket implementations? (Rust forum)
Traits: Defining Shared Behavior in the Rust book
Is there any way to create a type alias for multiple traits?
How is there a conflicting implementation of `From` when using a generic type?
Why do blanket implementations for two different traits conflict?
This question already has answers here:
Is there any way to restrict a generic type to one of several types?
(2 answers)
Closed 3 years ago.
We can restrict a type to one or more traits by where clause.
My questions are:
Is it possible to restrict a type to just primitive number types?
How?
No.
To use a parametric type, you need the trait to define the valid operations you want to call on it. So you need a trait (or more) with all the operations you want to call.
The “primitive” types in Rust are not special in any way. They define their operators via the traits from std::ops (though obviously using compiler intrinsics) just like any “non-primitive” numberic types.
In fact, the boundary between “primitive” and “non-primitive” numeric types is even somewhat blurred, since for targets that lack an FPU, the standard library may be implementing floating point types in code, and in Rust it can do it transparently to the user.
So really, there is no such thing as primitive number types. Number types are defined by providing whatever operators you need to call. So just restrict your type by the std::ops traits.
Since primitives are not trait types you cannot use as boundary to restrict a generic type. But you can directly implement for a specific type:
struct Struct<T>(T);
trait Printer {
fn print(&self);
}
impl Printer for Struct<i32> {
fn print(&self) {
println!("Printing for i32 value: {}", self.0);
}
}
fn main() {
let x = Struct(15_i32);
let _z = Struct(14.2_f64);
x.print();
//_z.print();//compile error
}
Playground
Alternatively you can use Borrow<S> trait as trick, you can restrict your generic parameter as like below : ( T: Borrow<S> means T can be borrowed as S ) .
impl<T> Printer for Struct<T>
where
T: Borrow<f64> + Debug,
{
fn print(&self) {
println!("Printing for f64 value: {:?}", self.0);
}
}
Playground
But since you can implement Borrow<f64> for any type, this kind of restriction may not be considered as strict.
Also just for the numeric primitives you can use traits from num-traits crate like ToPrimitive AsPrimitive
If you think about traits as compile time duck typing, then a better question would be: what are the exact traits you are looking for in a number? Most of the operations on them could be defined as trait constraints on your types, see: the standard operator traits.
Even if you would define a trait in an external crate and implement the behaviour for specific types only in that external crate, thinking that the trait implementation rules will help you there (i.e. a trait can only be implemented to a type if either the trait or the type or both are in your current crate) would still not limit anyone to implement your trait for their own types.
Therefore, I see no other option but to implement the behaviours without generics for each primitive number type. To avoid code duplication, I would probably use macros for this -- after all, if you think about it in some ways you would manually do what the compiler does while it monomorphises your generic code.
That being said I see no reason to limit behaviours to numbers but to certain traits and I would rely on them as I described it in the first paragraph.
I'd like to define a trait which forces its implementors to under no circumstances be sent to, or shared between, threads. It should suffice to mark the trait as !Send, but Rust doesn't seem to let me.
Is it possible?
Example (playground):
#![feature(optin_builtin_traits)]
// This is a syntax error
//trait ThreadThing : !Send {}
// This doesn't work either
trait ThreadThing { }
impl !Send for ThreadThing {}
No, you can't make !Send a condition of ThreadThing. The compiler just doesn't support that kind of logic.
If it would be possible for someone using your crate to make a type that is implicitly Send, contains no unsafe code in its implementation anywhere, and make it unsafe just by implementing ThreadThing for it -- in that case, you would make ThreadThing an unsafe trait to indicate that there is unsafe code somewhere that relies on an invariant that can't be described in the type system: the invariant "Things that are Send don't implement ThreadThing".
If, as is more likely, it's only unsafe to implement Send manually for a type that implements ThreadThing -- in that case, you don't need to do anything, because manually implementing Send is unsafe already. If an implementor of ThreadThing decides to manually implement Send, they take on the burden of guaranteeing not only their own invariants, but also ThreadThing's.
The answer is: yes, you can, under some very specific conditions. Whether you should need to do this is another matter.
You can define a negative trait implementation for another trait if the trait you are negating is:
an auto-trait.
from the current crate.
So the following will work (playground):
#![feature(optin_builtin_traits)]
auto trait Scary {}
trait ThreadThing { }
impl !Scary for ThreadThing {}
But it would not work if you were trying to do:
impl !Send for ThreadThing {}
Or if Scary was not an auto-trait.
Note however that, in general it should not be necessary to mark a trait !Send in this way. The concrete implementations of the trait will be marked Send or !Send by the Rust compiler based upon the contents of the implementing struct.
This code does not compile:
fn ref_on_int<T>(_: T) where T: AsRef<i32> {}
fn main() {
ref_on_int(&0_i32)
}
because
the trait bound `i32: std::convert::AsRef<i32>` is not satisfied
Why is it so?
This could be useful for example with a newtype like
struct MyInt(i32);
impl AsRef<i32> for MyInt {
/* etc. */
}
then you could indifferently pass a reference on an i32 or a reference on a MyInt, because in the memory we have in both cases an i32.
AsRef and Borrow are pretty similar at first glance, but they are used for different things. The Book describes the difference between them pretty well:
Choose Borrow when you want to abstract over different kinds of
borrowing, or when you’re building a data structure that treats owned
and borrowed values in equivalent ways, such as hashing and
comparison.
Choose AsRef when you want to convert something to a reference
directly, and you’re writing generic code.
In your case Borrow is a more reasonable choice because there is no conversion involved.
As for the question of why AsRef is not implemented between different integral types, I guess this would go against the intent of Rust to be expressive about casts; I think it's similar to the question Why can't I compare two integers of different types?.
Here's an authoritative answer by Aaron Turon:
Borrow provides a blanket implementation T: Borrow<T>, which is essential for making the above collections work well. AsRef provides a different blanket implementation, basically &T: AsRef<U> whenever T: AsRef<U>, which is important for APIs like fs::open that can use a simpler and more flexible signature as a result. You can't have both blanket implementations due to coherence, so each trait is making the choice that's appropriate for its use case.
I think that is one of the differences of AsRef and Borrow.
That is, Borrow<T> is implemented directly for &T, while AsRef<T> is not implemented for &T.
Funny thing is that AsRef<U> is implemented for &T if T implements AsRef<U>. That is, if you can use AsRef with a type, you can use it with a reference to the same time.
And another funny thing is that Borrow<T> is implemented for &T but also for T!