Alias generic trait with default types - rust

I have a trait that is generic: trait Trait<T> and I want to create another trait that specifies the generics: type Alias = Trait<String>. This would allow impl Alias for T and not have to specify the type parameters. I tried a couple ways of doing this and haven't found any that works.
This is not a duplicate of Type alias for multiple traits or Aliasing trait with associated types because doing trait Alias: Trait<T> requires people to implement Trait<T> anyway. I want to offer a trait that hides the generics.
A clearer code sample:
trait DefaultEvents = Events<UserStruct, ChannelStruct, IrcStruct>;
struct MyHandler;
impl DefaultEvents for MyHandler {
...
}

Here's my best suggestion, it's going to mean a bit more work on your part (with lots of manual trait inheritance), but it should achieve the user convenience that you want.
pub mod user_friendly {
pub trait GivesNum<T> {
fn get_num(&self) -> T;
}
pub trait GivesDouble {
fn get_double(&self) -> f64;
}
impl<S> GivesNum<f64> for S where S: GivesDouble {
fn get_num(&self) -> f64 { self.get_double() }
}
}
// now your library's user needs to do less
use user_friendly::*;
struct MyStruct { num: f64 }
impl GivesDouble for MyStruct {
fn get_double(&self) -> f64 { 2.0 * self.num }
}
fn main() {
let s = MyStruct{ num: 5.0 };
println!("MyStruct.get_num() = {}", s.get_num());
}
Try it on Rust Playground

Related

Implement methods for trait without additional traits

Looking for "blanket" implementation of the method(s) for trait.
Let's say for a trait
pub trait A {
fn do_a(&self);
}
want to have boxed method that wraps with box, without introducing any additional traits:
fn boxed(self) -> Box<Self>;
I can have another trait to achieve that (playground)
pub trait A {
fn do_a(&self);
}
pub trait Boxed {
fn boxed(self) -> Box<Self>;
}
impl<T> Boxed for T
where
T: A,
{
fn boxed(self) -> Box<Self> {
Box::new(self)
}
}
However, new trait Boxed is required for that.
You can add boxed directly to A with a default implementation so that structs won't need to implement it themselves:
trait A {
fn do_a(&self);
fn boxed (self) -> Box<Self>
where Self: Sized
{
Box::new (self)
}
}
struct Foo{}
impl A for Foo {
fn do_a (&self) {
todo!();
}
// No need to redefine `boxed` here
}
fn main() {
let foo = Foo{};
let _object: Box<dyn A> = foo.boxed();
}
Playground

Trait as generic parameter to struct object intialization

I have this struct:
use sp_runtime::traits::Block;
struct Bar<T: Block> {
e1: Vec<T>,
}
impl<T: Block> Bar<T> {
pub fn new() -> Self {
Bar { e1: Vec::new() }
}
}
Where Block is from the sp_runtime crate.
In main:
fn main() {
let var_1 = Bar::<Block>::new();
}
Full Code
This code throws compilation error that trait can't be made into an object. I'm new to Rust, much of online solution haven't addressed this issue. Kindly let me know how to get around initialization of bar object.
Your confusion likely stems from the fact that the sp_runtime crate has two items called Block. One is the trait sp_runtime::traits::Block and the other is a struct, sp_runtime::generic::Block, which implements that trait.
Traits can be used as a constraint on a type parameter, but they cannot be used as a type argument.
So, in your definition of Bar<T>, you can constrain T with sp_runtime::traits::Block, but when you construct an instance of Bar<T>, T needs to be the struct instead.
use sp_runtime::traits::Block;
struct<T: Block> Bar {
e1: Vec<T>,
}
impl<T: Block> Bar<T> {
pub fn new() -> Self {
Bar {
e1: Vec::new(),
}
}
}
fn main() {
use sp_runtime::generic::Block;
let var_1 = Bar::<Block>::new();
}
However, given that this is the only implementation of the trait in the crate, you can just avoid mentioning the trait altogether and use the concrete struct type (unless you plan on implementing it yourself or depending on implementations from other crates):
use sp_runtime::generic::Block;
struct Bar{
e1 : Vec<Block>,
}
impl Bar {
pub fn new() -> Self{
Bar {
e1: Vec::new(),
}
}
}
fn main() {
let var_1 = Bar::new();
}

Why sized trait is required for a builder function to generate Rc<T>?

This code works fine (playground):
use std::rc::Rc;
trait Foo {
fn foo(&self);
}
struct Bar<T> {
v: Rc<T>,
}
impl<T> Bar<T> where
T: Foo {
fn new(rhs: Rc<T>) -> Bar<T> {
Bar{v: rhs}
}
}
struct Zzz {
}
impl Zzz {
fn new() -> Zzz {
Zzz{}
}
}
impl Foo for Zzz {
fn foo(&self) {
println!("Zzz foo");
}
}
fn make_foo() -> Rc<Foo> {
Rc::new(Zzz{})
}
fn main() {
let a = Bar::new(Rc::new(Zzz::new()));
a.v.as_ref().foo()
}
but if I make a wrapper to generate Rc like below, the compiler complains about missing sized trait (playground)
fn make_foo() -> Rc<dyn Foo> {
Rc::new(Zzz::new())
}
fn main() {
let a = Bar::new(make_foo());
a.v.as_ref().foo()
}
in both cases, Bar::new received parameters with same type Rc, why the rust compiler reacts different?
By default, all type variables are assumed to be Sized. For example, in the definition of the Bar struct, there is an implicit Sized constraint, like this:
struct Bar<T: Sized> {
v: Rc<T>,
}
The object dyn Foo cannot be Sized since each possible implementation of Foo could have a different size, so there isn't one size that can be chosen. But you are trying to instantiate a Bar<dyn Foo>.
The fix is to opt out of the Sized trait for T:
struct Bar<T: ?Sized> {
v: Rc<T>,
}
And also in the context of the implementations:
impl<T: ?Sized> Bar<T>
where
T: Foo
?Sized is actually not a constraint, but relaxing the existing Sized constraint, so that it is not required.
A consequence of opting out of Sized is that none of Bar's methods from that impl block can use T, except by reference.

How can I implement Borrow for a generic container in the case of the use of associated types?

I would like to implement Borrow for UserFriendlyDataStructure to provide access to the internal_data field within a function that should be agnostic with respect to the data provider. The type of the internal_data field is determined by the type associated to trait TraitA. Note that the Sealed trait ensures that none of these traits here can be implemented by other crates; this is functionality that strictly I provide. Furthermore, the type TraitA::Data is restricted by the empty trait DataTrait to prevent UserFriendlyDataStructure from being used as that type.
The following example explains best:
use std::borrow::Borrow;
use std::marker::PhantomData;
mod private {
pub trait Sealed {}
}
pub trait DataTrait: private::Sealed {}
pub trait TraitA: private::Sealed {
type Data: DataTrait;
}
pub struct UserFriendlyDataStructure<A: TraitA> {
internal_data: A::Data,
_a: PhantomData<A>,
}
impl<A: TraitA> Borrow<A::Data> for UserFriendlyDataStructure<A> {
fn borrow(&self) -> &A::Data {
&self.internal_data
}
}
pub fn important_function<A: TraitA, T: Borrow<A::Data>>(data: &T) {
let _internal_data = data.borrow();
// Do lots of work.
}
#[cfg(test)]
mod tests {
use super::*;
pub struct TestData(u32);
impl super::private::Sealed for TestData {}
impl DataTrait for TestData {}
pub struct TestProvider;
impl super::private::Sealed for TestProvider {}
impl TraitA for TestProvider {
type Data = TestData;
}
#[test]
fn basic_test() {
let ufds: UserFriendlyDataStructure<TestProvider> = UserFriendlyDataStructure {
internal_data: TestData(100),
_a: PhantomData::default(),
};
important_function::<TestProvider, _>(&ufds);
}
}
Unfortunately, the compiler complains:
error[E0119]: conflicting implementations of trait `std::borrow::Borrow<UserFriendlyDataStructure<_>>` for type `UserFriendlyDataStructure<_>`:
--> src/lib.rs:19:1
|
19 | impl<A: TraitA> Borrow<A::Data> for UserFriendlyDataStructure<A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::borrow::Borrow<T> for T
where T: ?Sized;
Is there a way to achieve what I am trying to do?
The compiler can be cajoled into accepting the code by introducing a redundant second type parameter that is constrained to be identical to A::Data:
impl<A, D> Borrow<D> for UserFriendlyDataStructure<A>
where
A: TraitA<Data = D>,
D: DataTrait,
{
fn borrow(&self) -> &A::Data {
&self.internal_data
}
}
I don't know why this works, and simply constraining A::Data: DataTrait doesn't. I think the compiler should accept both versions.
(Full code on the playground)
Edit: The fact that we need the redundant type D in the above code appears to be a shortcoming of the current compiler implementation, and is hopefully resolved once the experimental type inference engine chalk gets integrated in the compiler.

Create a generic struct with Option<T> without specifying T when instantiating with None

I have a
struct Foo<T>
where
T: // ... some complex trait bound ...
{
a: Bar,
b: Option<T>,
}
When attempting to instantiate the struct with a b: None the compiler complains that it cannot infer the type and requires a type hint e.g. via the turbofish syntax. That is onerous on the caller because they will have to find a type that fulfills the trait bounds and import it despite not caring about that optional functionality.
I think what I am looking for would be a bottom type that automatically fulfills any trait bounds but cannot be instantiated so that None::<Bottom> could be used, but I have not found such a type in the documentation.
There's a feature in the works that allows specifying the never type as !. This is not present in stable Rust, so you need to use a nightly and a feature flag:
#![feature(never_type)]
fn thing<T>() -> Option<T> {
None
}
fn main() {
thing::<!>();
}
However, this doesn't work for your case yet (this is part of the reason that it's unstable):
#![feature(never_type)]
trait NothingImplementsMe {}
fn thing<T>() -> Option<T>
where T: NothingImplementsMe,
{
None
}
fn main() {
thing::<!>();
}
error[E0277]: the trait bound `!: NothingImplementsMe` is not satisfied
--> src/main.rs:12:5
|
12 | thing::<!>();
| ^^^^^^^^^^ the trait `NothingImplementsMe` is not implemented for `!`
|
= note: required by `thing`
The very first unresolved question on the tracking issue is:
What traits should we implement for !?
Since this feature is both unstable and doesn't do what you want, you may want to consider creating your own bespoke "bottom" type:
trait AlmostNothingImplementsMe {
fn foo();
}
struct Nope;
impl AlmostNothingImplementsMe for Nope {
fn foo() { unimplemented!() }
}
fn thing<T>() -> Option<T>
where T: AlmostNothingImplementsMe,
{
None
}
fn main() {
thing::<Nope>();
}
To improve the UX of this, I'd suggest creating a builder of some type that starts you off with the faux-bottom type:
mod nested {
pub trait AlmostNothingImplementsMe {
fn foo();
}
pub struct Nope;
impl AlmostNothingImplementsMe for Nope {
fn foo() { unimplemented!() }
}
pub fn with_value<T>(t: T) -> Option<T>
where T: AlmostNothingImplementsMe,
{
Some(t)
}
pub fn without_value() -> Option<Nope> {
None
}
}
fn main() {
nested::without_value();
}
You can see this similar pattern in crates like Hyper, although it boxes the concrete type so you don't see it from the outside.
One option to avoid the need to the turbofish operator is to have a type alias:
trait MyTrait {}
impl MyTrait for () {}
struct Foo<T: MyTrait> {
i: isize,
o: Option<T>,
}
type Bar = Foo<()>;
fn main() {
let foo_default = Bar { i: 1, o: None };
}
I used () as the default for simplicity, but ! (when available) or your own bottom type as in #Shepmaster's answer may be better.
A constructor function could also work if you don't mind Foo::new_default(i) or similar.

Resources