-
Notifications
You must be signed in to change notification settings - Fork 125
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
Support custom bounds for Display-like traits #93
Comments
I believe I understand the problem, but I think a much simpler and more elegant solution would be to automatically derive: impl<A, B, C> fmt::Display for Bar<A, B, C>
where Foo<A, B>: Display,
C: Display,
{ ... } It could be that I'm misunderstanding though. |
To confirm my solution works as well I just tried the following code and it compiles (without the where it doesn't): #[derive(Display)]
struct Foo<A>(A);
struct Bar<A>(Foo<A>);
impl<A> ::core::fmt::Display for Bar<A>
where
Foo<A>: ::core::fmt::Display,
{
#[allow(unused_variables)]
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "{}", self.0)
}
} |
Didn't even know that is possible 😵 |
@JelteF however, still specifying bounds explicitly may be very desirable in quite exotic cases like the following:
These cases are too rare, however, having the ability to manually specify the bounds for the implementation is vital, as for me. So, the plan is to land (one step - one PR):
|
Sounds perfect to me! |
From #95 (comment):
@ffuugoo would you be so kind to explain this point further with primitive examples which illustrate the problem? |
Given: #[derive(Display)]
struct Foo<'a, T> {
field: &'a T,
} Result:
|
I just realized, that this case is, actually, no different from generic |
@ffuugoo I guess cases like |
@ffuugoo even more, I think we should take this pattern as common:
|
First half of #93. Modified `Display` macro, so that for each field of the following types _or of reference to such types_ a where clause is generated bounding field's type by `Display` trait: * `T` * `T::AssociatedType` and `<T as Trait>::AssociatedType` * `::path::SomeOtherType<T>` and `::path::SomeOtherType<&T>` E.g., for a structure `Foo` defined like this: ```Rust #[derive(Display)] struct Foo<'a, T1, T2: Trait, T3> { field1: T1, field2: <T2 as Trait>::Type, field3: Bar<T3>, field4: &'a T1, field5: &'a <T2 as Trait>::Type, field6: &'a Bar<T3>, } ``` Following where clauses would be generated (notice, that for reference types the _referred_ type is bound): * `T1: Display` * `<T2 as Trait>::Type: Display` * `Bar<T3>: Display`
Synopsis
Current
#[derive(Display)]
is smart enough with its default behavior. However, due to absence of compile-time reflection, it's impossible to handle all the cases really gracefully.Consider the following:
The
Bar
won't compile with an error:This is because we're unable to infer
Display
requirements forFoo<A, B>
inFoo()
variant knowing only tokens.Fortunately, such situations are tend to be resolved with custom
bound
attributes (see#[serde(bound = "T: Serialize")]
, for example) in Rust ecosystem.Proposal
Let's extend
#[derive(Display)]
with#[display(bound)]
attribute, which may be used in the following manner:If bound is not specified (no semicolon), we apply the bound of the derived trait.
The text was updated successfully, but these errors were encountered: