I'm not an experienced Rust developer, I'm just learning the language, but here we're discussing syntactic sugar, so I don't think specific expertise is required.
Problem
#[derive(Debug, Clone)]
struct AnB {
a: u32,
b: u32
}
trait ArithmeticallyAddable {
fn add(&self) -> u32;
}
trait Concatenatable {
fn add(&self) -> u32;
}
impl ArithmeticallyAddable for AnB {
fn add(&self) -> u32 {
self.a + self.b
}
}
impl Concatenatable for AnB {
fn add(&self) -> u32 {
match (self.a.to_string() + &self.b.to_string() as &str).parse::<u32>() {
Ok(v) => v,
Err(..) => 67,
}
}
}
fn main() {
let a = 2;
let b = 2;
let anb = AnB {a:a, b:b};
println!("{a} + {b} = {} if ArithmeticallyAddable::add was called", ArithmeticallyAddable::add(&anb));
println!("{a} + {b} = { } if Concatenatable::add was called", Concatenatable::add(&anb));
}
This is how a name conflict in Rust is usually handled when it occurs. Quite ordinary code, but the used syntax strongly differs from the standard anb.add(). First, this is no longer a method call, second, here you need to specify that anb is passed explicitly as an immutable reference (&self), whereas in anb.add() the compiler specifies this automatically. (&v as &dyn Trait).method() solves the first but not the second, plus it's cumbersome, and v.Trait::method() simply does not exist in Rust, which is reasonable (UPDATE: actually it's not, v.Something::something_else seems never to be used in Rust).
For such an idiomatic language as Rust, where everything is logical (or supposed to be), it's odd that the penalty for poor naming is not just an additional specification of the specific trait whose method is used, but a complete change in the method call syntax, as well as a requirement to do manual work the compiler would handle.
Proposed Solution
-
Currently syntax
(v as Trait).method()results in an errorexpected a type, found a trait. If replaced with ambiguous method name resolution, no existing code would break. -
For multiple use,
use Trait::method for Type;should makemethodfromTraitthe default option for all values of typeTypeacross the scope.
Show some activity under the topic if you have any ideas or you simply agree with the fact that this should be added to the language
UPDATE
At first glance, v.<Trait::method>() looked as ugly to me as v.Trait::method(), but I looked at it again and realized that it's clean and straightforward. It changes only the source of the ambiguity -- the method name - and clarifies that there's nothing called Trait, only <Trait::method> as a single symbol, so...
Proposed Solution No. 2
-
v.<Trait::method>()is used for a single use -
For multiple uses,
use Trait::method for Type;makesmethodfromTraitthe default option for all values of typeTypeacross the scope. Specifying exact variables is also possible, e.g.,use Trait::method for v;. -
The
Traitsymbol comes from the scope.