Just as a counterexample, consider forwarding serde::de::Visitor
. With this adjustment it's (without the 'de
-dependent methods because lifetime complexity)
impl<'de> Visitor<'de> for MyType {
use self.raw::{
expecting,
visit_bool,
visit_i8,
visit_i16,
visit_i32,
visit_i64,
visit_u8,
visit_u16,
visit_u32,
visit_u64,
visit_f32,
visit_f64,
visit_char,
visit_str,
visit_string,
visit_bytes,
visit_byte_buf,
visit_none,
visit_some,
visit_unit,
visit_newtype_struct,
visit_seq,
visit_map,
visit_enum,
};
serde_if_integer128!(use self.raw::{visit_u128, visit_i128});
}
I really don't want to write out the explicit version on my phone; it's a lot more boilerplate to read, even if your IDE can generate it for you.
For a more reasonable example, consider forwarding all the Iterator
methods for your IntoIter
wrapper type.
The real advantage comes from forwarding a large trait, but it adds clarity to the single case as well as the large one. I think it's a clear positive in some form at least.
The syntax of allowing .
in a path (use self.member::{func}
) doesn't require backtracking (or equivalently, infinite lookahead). It's even LL(3) in the simple case (use
, self
, .
; the .
means it's a delegation use
). Even in worst case "you don't know what kind of use tree it is until after you parse the main tree", it doesn't require backtracking/infinite lookahead; you just delay the decision. Parse the use tree and then decide what kind of use treee it is. Backtracking is a problem when you need to reinterpret how you've parsed what you've already passed. If it parses the same on all paths, just delay the decision.