Possible bug in generic implementation of Default? [duplicate] - rust

This question already has answers here:
Deriving a trait results in unexpected compiler error, but the manual implementation works
(2 answers)
Closed 5 years ago.
Given the following struct Foo<T> that derives Default:
#[derive(Default)]
struct Foo<T> {
bar: Option<T>,
}
Why does this compile
fn create<T>() -> Foo<T> {
Foo {
bar: Option::default(),
}
}
but this doesn't?
fn create_alt<T>() -> Foo<T> {
Foo::default()
}
In my mind they are both doing the exact same thing--it shouldn't matter if T implements Default (which is what the compiler wants me to specify) because Option<T> implements Default.
Here is a link to the Rust Playground with this example.

This is a known issue, and it's hard to fix. Issue #26925
In short, #[derive] uses incorrect bounds: it assumes that in order to implement Default for Foo<T>, T must be Default, when in reality Option<T>: Default is sufficient.
The problem with fixing it is that it's possible to have struct members of private types, and using #[derive] on a public generic struct that has private members could partially expose that private interface. For example,
trait MyTrait {}
struct MyType<T> {}
impl<T> Default for MyType<T> where T: MyTrait {}
#[derive(Default)]
pub struct PubType<T> {
member: MyType<T>,
}
If #[derive(Default)] does the right thing, you effectively have this impl block for a public type that exposes a private trait:
impl Default for PubType<T>
where T: MyTrait
{ ... }
Probably the best way to get around this right now is to avoid using #[derive] in this case and write the impl yourself.

Related

Is it possible to declare a trait that accepts more methods that the ones declared in its body?

Something like:
pub trait MyTrait {
// No methods defined/declared
}
impl MyTrait for MyType {
fn method_one_not_declared_neither_defined(&self) {
// body of trait method impl here
}
fn method_two_not_declared_neither_defined(&self) {
// body of trait method impl here
}
}
While the trait itself cannot be extended, you can still add behaviour to all types which implement a trait. This can be done using extension traits and blanket implementations.
trait MyTrait {}
struct MyType;
impl MyTrait for MyType {}
trait TraitExt {
fn foo(&self) {
println!("Foo");
}
}
impl<T> TraitExt for T where T: MyTrait {}
fn main() {
let t = MyType {};
t.foo();
}
Playground
This is not the same as extending MyTrait however - TraitExt must be in scope for foo to be called.
No. Only methods declared in trait definition might be implemented when implementing trait for a type. You can add this methods as normal type's methods, but not as trait's. Think of a trait as a public interface. You must implement all of trait's methods (besides those with default implementation) and cannot add anything more.

Derive a trait by delegating to a struct member which implements that trait

Consider the following struct:
struct SectoredStream<T> {
sector_sz: usize,
inner: T,
}
When T implements Read I can implement Read for SectoredStream<T> as follows:
impl<T: Read> Read for SectoredStream<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}
This is a simple example, but in general I may want to implement a complex trait by delegating all of the trait methods to one of the members of my struct which implements that trait. It seems clear that this type of boilerplate code could be generated by a macro, and I can see how to do it for a particular trait using a declarative macro. I believe the general case will require a procedural macro, but I doubt this is a unique problem. So, is there already a crate which implements this macro?

What does `impl ... for` mean?

I see the following pattern coming up a lot in Rust codebases, but I can't find an explanation why this is used.
For what end does one use the impl ... for construction?
Pseudocode:
impl Handler {
pub fn method1() -> () {
}
}
impl Dummy for Handler {
pub fn method2() -> () {
}
}
impl Struct ... adds some methods to Struct. These methods aren't available to other types or traits.
impl Trait for Struct .. implements the trait Trait for the struct Struct. This results in the methods of the trait being available for Struct.
So, even though these two syntaxes look similar, they do 2 completely different things.
impl Struct ... adds new (not previously defined) methods to the type, while the other adds previously defined methods (from the trait) to the type.

Can i define a trait implementing another trait’s associated function when there is already a generic implementation for the trait Im implementing?

Context: I am working with an external crate that defines a trait ExternalTrait
eg
pub trait ExternalTrait {
fn associated_func() -> i32;
}
I have several types that have almost identical implementations of said trait, differing only by a single value, so I want to defined my own trait implementing the external one where the only required definition is the value that differs.
e.g.
trait MyImplementation {
fn custom_value() -> i32;
}
One way i attempted to do this that does not work is
impl ExternalTrait for dyn MyImplementation {
fn associated_func() -> i32 {
&Self::custom_value()
}
}
which fails because MyImplementation, having an associated function, is not object safe.
What does work is
impl<T> ExternalTrait for T
where
T: MyImplementation,
{
fn associated_func() -> i32 {
T::custom_value()
}
}
which is great, except that the external crate I'm working with already has a generic implementation for that trait, like this:
impl<'a, Y> ExternalTrait for &'a Y
where
Y: ?Sized,
Y: ExternalTrait,
{
fn associated_func() -> i32 {
10
}
}
which understandably conflicts with the one I'm defining. So the question is, is there a way to support my use-case, aside from using macros?
Cheers
e: additional context. The above was just me trying to come up with a minimal example. The actual external trait that I'm running into this in practice is https://docs.rs/juniper/0.15.1/juniper/trait.GraphQLType.html and conflicting implementation is https://docs.rs/juniper/0.15.1/juniper/trait.GraphQLType.html#impl-GraphQLType%3CS%3E-for-%26%27e%20T. It is possible to implement it for a concrete struct just fine, e.g.
impl GraphQLType<DefaultScalarValue> for MyStruct

How do I use a BorrowMut supertrait to access struct fields in a trait default method?

Consider the following Rust code
trait Trait {
fn show_name(&self) {}
}
struct Foo {
name: String,
things_and_stuff: usize,
}
impl Trait for Foo {
fn show_name(&self) {
println!("{}", self.name);
}
}
struct Bar {
name: String,
other_field: i32,
}
impl Trait for Bar {
fn show_name(&self) {
println!("{}", self.name);
}
}
The two show_name functions have exactly the same code. It would be convenient if I could put that method as a default method on Trait, but that's not possible because traits cannot access struct fields.
We could declare a get_name(&self) -> &str method on Trait and implement it on Foo and Bar, but that doesn't fix the problem of having duplicated code because both implementations of get_name will be the same.
It would be nice to avoid the code duplication. Another question has already asked if field access is possible in traits, and the answer was basically "no".
However, I found a comment in the rust-internals forum suggesting that it's already possible. Here's the code:
struct Fields {
name: String,
}
trait Trait: BorrowMut<Fields> {
// methods go here
}
impl<T> Trait for T where T: BorrowMut<Fields> {}
Presumably there's a way to make a type T be BorrowMut<Fields> and use that to allow Trait to access Fields's fields, but so far I'm not sure how that would work.
How is the code snippet shown above supposed to solve the problem of getting field access in traits?
I know there are discussions of adding field access in traits to the language (rust-internals, RFC, another RFC), but I'd like to know what's possible now.
the answer was basically "no"
The answer actually says (emphasis mine):
A default implementation can only use methods that are defined on the trait or in a super trait.
That's what your snippet does:
trait Trait: BorrowMut<Fields>
To make it work, follow the advice from the post you are referencing:
all types which choose to implement BorrowMut<Foo>
Thus, you need to implement the trait for each of your types. I switched to Borrow because you don't need mutability here:
use std::borrow::Borrow;
struct Fields {
name: String,
}
trait Trait: Borrow<Fields> {
fn show_name(&self) {
let fields: &Fields = self.borrow();
println!("{}", fields.name);
}
}
struct Foo {
fields: Fields,
things_and_stuff: usize,
}
impl Borrow<Fields> for Foo {
fn borrow(&self) -> &Fields {
&self.fields
}
}
struct Bar {
fields: Fields,
other_field: i32,
}
impl Borrow<Fields> for Bar {
fn borrow(&self) -> &Fields {
&self.fields
}
}
impl<T> Trait for T where T: Borrow<Fields> {}
I'm almost certain you won't like this solution because it
doesn't fix the problem of having duplicated code because both implementations [...] will be the same
You may prefer to write a macro if your goal is to reduce the number of duplicate characters in your code.
See also:
I implemented a trait for another trait but cannot call methods from both traits
Is it possible to access struct fields from within a trait?

Resources