This is my experience so far with specialization (and traits in general). My use case is the following: given two traits A
and B
, and a generic function:
foo<T: A>(x: T) {}
I want to “specialize” foo
for T: A + B
, so that foo(x)
chooses one function or another depending on whether x
implements A
or A + B
. Nothing fancy I would say. Obviously, this:
fn foo<T: A+ B>(x: T) {}
doesn’t work (specialization doesn’t work this way). So let’s get started.
First, we’ll need a trait:
trait Foo {
fn foo(self); // need to use self or we break UFCS
}
which we can then implement for all types that implement A
:
impl<T: A> trait Foo for T {
default fn foo(self) {}; // allow specialization here
}
and then specialize that for all types that implement A + B
:
impl<T: A + B> trait Foo for T {
fn foo(self) {}; // specialize here
}
So now, Foo::foo(x)
and x.foo()
both work, but foo(x)
still doesn’t, so the missing piece of the puzzle is:
fn foo<T: Foo>foo(x: T) {
Foo::foo(x)
}
And in just 12 lines (1 trait declaration, 2 trait implementations, and an extra function), we are done!
I think this amount of boilerplate is bearable, but I wish that the 2 line version:
fn foo<T: A>(x: T) {}
fn foo<T: A + B>(x: T) {}
will some day work (since this is what I wanted to do).
I would like trait methods and functions to be equally powerful. Right now this isn’t the case and if you want the power you need to chose trait methods independently of whatever makes more sense. I would also like to have UFCS in Rust. Currently, the function call syntax degrades significantly when moving from trait methods that take self
(which are the “most uniform to call”: can’t be called with the foo(x)
syntax, but can at least be called with Trait::foo(x)
) to both, trait methods that don’t take self
(but, e.g., Self
, which can’t be called with the .foo()
syntax) and functions that take T: Trait
(which can’t be called with the .foo()
syntax either). Both the specialization and the function call syntax feel very “asymmetric”: you really need to pick the right combination of language features and workaround to be able to write an API that is symmetric/nice to use.