Why implementing a generic trait for a generic type using the same lifetime specifier is not preferred?

Serde's documentation(Deserializer lifetimes · Serde) mentions that when implementing Deserialize<'de> for a type Q<'a>, using the same lifetime specifier for Deserialize<'de> and Q<'de> is not preferred, but it doesn't explain why.

The 'de lifetime should not appear in the type to which the Deserialize impl applies.

// Do not do this. Sooner or later you will be sad.
impl<'de> Deserialize<'de> for Q<'de> {

// Do this instead.
impl<'de: 'a, 'a> Deserialize<'de> for Q<'a> {

Here is the Deserialized<'de> trait's definition:

pub trait Deserialize<'de>: Sized {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>;
}

Is there any example could illustrate the drawback of the first style?
Is the first style not preferred for all generic trait, or just this specific trait?

Well, let's take Q<'a> = &'a str as an example. Should you not be able to deserialize data that is valid for the lifetime 'long as the type &'short str?

struct Q<'a>{ name:&'a str}

case 1

impl<'de> Deserialize<'de> for Q<'de> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where D: Deserializer<'de>{}
}
let q = Q::deserialize(deserializer); // 

case 2

impl<'de, 'a> Deserialize<'de> for Q<'a> where 'de: 'a {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where D: Deserializer<'de>{}
}
let q = Q::deserialize(deserializer); 

In above code, no matter q's name is borrowed from deserializer by 'de in case 1, or by 'unknown( 'unknown < 'de , 'unkonw > 'q) in case 2 , wouldn't that borrow be released once q is out of scope? Does it make a difference?

In the case where you can deserialize it at all, it does not make a difference.

The problem is that in some circumstances, the appropriate Deserialize impl will simply be missing, and you wont be able to deserialize.

Does "missing" mean that the case 1 cannot deserialize Q from some Deserializer?

For example, if you derive Deserialize for this struct:

struct TwoQs<'a, 'b> {
    q1: Q<'a>,
    q2: Q<'b>,
}

Then TwoQs<'a, 'b> doesn't implement Deserialize unless 'a = 'b, since the first field only implements Deserialize when 'de = 'a and the second field only implements Deserialize when 'de = 'b, which together imply that 'a = 'b.

1 Like