Function behaviour depending on whether a trait is implemented - rust

Given a situation like this one :
trait Basic {
// Some functions
}
trait Derived : Basic {
// some other functions
}
fn do_someting<T : Basic>(target: &mut T) {
// do stuff
}
Is it possible to have the do_something function behave differently depending on whether target implements the trait Derived or not (the information being known at compilation time) ?
I guess something similar could be achieved in C++ using template specialization, but I don't see a Rust equivalent.

AFAIK this is not currently possible. Defining fn do_something<T : Derived> alongside your existing function leads to compilation error:
error: duplicate definition of value `do_someting`
because both versions can be used for Basic.
There are some proposals to allow explicit bounds like <T: Basic + !Derived> that will allow you to resolve this conflict.
But I personally hope that impl overloading/specialization will be possible some day after 1.0 version is released.

Related

How can I split up a large impl over multiple files?

I really don't like monolithic implementations of the functions for a class (in C++ speak). In that language I can split things up as I like; in Rust there are strict rules about what goes in what files.
I have about 2000 lines (no comments/ docs) of impl for a struct. Logically they can be broken up into different sets; functions for managing aspect A, functions for managing aspect B, ... They all noodle on the struct's data big time, so chopping the struct up further wont help.
I saw in one answer that you can have
// in thing.rs
struct Thing{
.......
}
impl Thing{
fn1
fn2
}
// in more_thing.rs
use crate::thing::*;
impl Thing{
fn3,
fn4
}
// in lib.rs
mod thing;
mod more_thing;
This works, almost (I was surprised it worked at all). Its a kind of half way house. The problem is that for the methods in more_thing.rs I have to declare the fields of Thing all pub. Which is doable but not great. Are there any other options?
I know I can limit the pub scope but still it blows encapsulation.
All non-pub items in a module are still visible in its submodules. Just make more_thing a submodule of thing instead of a sibling. You can do this by putting it in a directory named thing, and putting the mod declaration inside thing.rs:
// thing.rs (or thing/mod.rs; see below)
pub struct Thing {
field: i32,
}
// Note the lack of `pub`: `more` is only an implementation detail
mod more;
// thing/more.rs
use super::Thing;
impl Thing {
// Although it is defined in a non-`pub` module, this method will be visible anywhere
// `Thing` is because it is marked `pub` and is a member of `Thing`. You can use
// `pub(crate)` or `pub(super)` instead to get different levels of visibility, or
// leave it private and it will only be available in the current module (thing::more)
pub fn field(&self) -> i32 {
// because more is a submodule of thing, non-`pub` members are visible here.
self.field
}
}
If you wish to keep all the Thing-related files in the thing directory, you can rename thing.rs to the special filename thing/mod.rs and it will work in exactly the same way.
All methods are private by default in Rust, which means they are only accessible in the scope of their containing module (which is never larger than a file), in this case thing.rs. thing.rs is just as remote to more_thing.rs as any libraries and external code; it may as well be a separate crate. In essence, you are trying to declare a private method on an external item, which of course fails.
However, this can be a bit confusing because when it comes to orphan rules, you can always implement traits for any item in the same crate, not just the same module. This is because trait implementations are always public (as long as you can access both the trait and the item implementing it; the actual orphan rules are a bit more complicated but this is the basic idea).
In essence: trait implementations are public, but method implementations are private by default. In order to implement public things you need at least public access, and in order to implement private things you need private access.
Instead, one solution is to simply declare a function that takes your item as an argument. For example, in more_thing.rs:
use super::thing::Thing;
fn foo(thing: &Thing) {
// ...
}
Why not put impl blocks in the same file?
in thing.rs
struct Thing {
.......
}
impl Thing {
fn1
fn2
}
impl Thing {
fn3
fn4
}
The methods are splited though there is still a large file.

How do I call a getter from another Substrate module?

I have two modules, MyCore and Special. MyCore has a public getter:
pub fn get_core_account() -> Option<T::AccountId>
Which gets an accountId. If I call this from Special in a simple manner:
let core_account = MyCore::get_core_account();
then rustc complains that it can't infer the type, which is odd because the public setters don't need further info. So I make the type explicit
let core_account: Option<T::AccountId> = MyCore::get_core_account();
But this triggers demands for type specifiers on the call, so we elaborate:
let core_account: Option<T::AccountId> = MyCore::<T>::get_core_account();
At which point rust complains that it can't find get_core_account, because Special doesn't have a restriction to implement MyCore::Trait. But I don't want Special to implement MyCore::Trait! I want to call a getter!
Perhaps I'm missing something regarding the use of T here - in theory, Special is a trait templated over some T, which we can implement using a Test class if we implement the required types.
Does Special really need to implement MyCore::Trait?
What you want to do is possible, yet you are probably doing something wrong which is not clearly demonstrated in the question. Would be very helpful if you post the Trait definitions of both modules.
Does Special really need to implement MyCore::Trait?
No. You might have to make it a trait bound though.
Basically, you have two options in such cases:
If your Core is something that all other modules will depend on, similar to frame-system, you can explicitly depend on it. Note that this path should be taken with care and you don't want to create too big of a monolithic software with this mindset. Nonetheless, in that case, you can just do:
// in special.rs
// This is needed because then we can pass `T` into `mycore::Module<_>`.
pub trait Trait: mucore::Trait {
...
}
// and then later on you can call:
<mycore::Module<T>>:: get_core_account()
This seems like the approach that you wanted to take.
Alternatively, you can bind the two modules together without this explicit dependency. This is useful for when you want your Special to receive the getter eventually, but you don't really care who provides it. Or in other words, if multiple candidates can provide this getter and you want to be generic over it.
For this, you first need a common trait definition.
// in some common dependency
trait CoreGetterProvider<AccountId> {
fn getter() -> Option<AccountId>;
}
and your Special would express:
pub trait Trait {
// .. other stuff. Assuming that it has a common AccountId with Core.
type Getter: CoreGetterProvider<Self::AccountId>
}
And your Core implements it
// in Core.rs
impl<T: Trait> CoreGetterProvider<T::AccountId> for Module<T> { ... }
Finally, when building the runtime, you can pass the Core module to Special.
impl core::Trait for Runtime { ... }
impl special::Trait for Runtime {
type Getter = core::Module<Runtime> // or just `Core`. construct_runtime! creates this type alias.
}

Differences in syntax for invoking trait method on generic type

I'm trying to understand the need for the Trait:: and <T as Trait>:: method invocation syntax. In particular, I'm looking at the following function from this answer:
fn clone_into_array<A, T>(slice: &[T]) -> A
where
A: Default + AsMut<[T]>,
T: Clone,
{
assert_eq!(
slice.len(),
std::mem::size_of::<A>() / std::mem::size_of::<T>()
);
let mut a = Default::default();
<A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
a
}
It seems that the middle two method invocation lines can be rewritten as:
let mut a = A::default();
a.as_mut().clone_from_slice(slice);
I believe this is more readable, as we already know that A implements Default and AsMut<[T]> and we can invoke as_mut directly as a method instead of having to pass a to it explicitly.
However, am I missing a good reason for the linked answer to have written it more verbosely? Is it considered good style? Are the two semantically different under certain conditions?
I agree with your rewrites — they are more clear and are what I would recommend for that function.
am I missing a good reason for the linked answer to have written it more verbosely?
My guess is that the author simply was tired of writing that function and stopped. If they took a look at it again, they might refine it to be shorter.
Is it considered good style?
I don't think there's a general community stylistic preference around this yet, other than the general "shorter is better until it isn't".
Are the two semantically different under certain conditions?
They shouldn't be.
There are times where the <>:: syntax is needed because otherwise it would be ambiguous. One example from a recent question:
let array = <&mut [u8; 3]>::try_from(slice);
Another time is when you don't have a nicely-named intermediate type or the intermediate type is ambiguous across multiple traits. One gross example is from a where clause but shows the same issue as an expression would:
<<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output: QueryId,
See also:
How to call a method when a trait and struct use the same name?

Why does #[derive(Show)] not work anymore?

With today's Rust nightly the following code doesn't compile anymore:
#[derive(Show)]
enum S {
A,
B
}
fn main() {
println!("{}", S::A);
}
Instead it gives me the following error message:
error: the trait `core::fmt::String` is not implemented for the type `S`
Is there a way to get the old behaviour? Surely it can't be required to implement this by hand for each type.
The old Show trait was split into Display and Debug.
Display is designed for user-facing output, and uses the blank/default format specifier (e.g. {}, {:.10} {foo:} are all using Display)
Debug is designed for debugging/internal output and uses the ? format specifier (e.g. {:?}, {:.10?}, {foo:?} are all using Debug)
Hence, to use the implementation created by #[derive(Debug)] one should write println!("{:?}", ...), instead of the old println!("{}", ...).
Only Debug can be #[derive]d since output like Foo { x: 1, y: 2 } is unlikely to be the correct user-facing output, for most situations (I'm sure it is for some, but then the programmer can write the implementation of Display to do that themselves, or even call directly into the #[derive]d Debug implementation).
This was originally described in RFC 504 and there is ongoing discussion in RFC 565, making the guidelines stated above more concrete.
The answer is to use {:?} instead of {} in format!.

Optional function argument that is specified as a trait instead of a concrete type

I have been watching Rust for the past few months but I just started into an actual project. I am not sure if the terminology in the title is correct. Please let me know how it can be corrected.
I am writing a rust wrapper around the ENet library (http://enet.bespin.org). My goal is to keep the rust API as similar to the C API as possible except to refactor functions that take C style handle pointers into member functions of structure objects. I want to keep the API similar so that the official C documentation will apply equally well to the rust wrapper.
ENet exposes a single function to create either a client host or a server host. When creating a server you pass a pointer to an IP Address structure to the function. When creating a client you pass NULL.
I am trying to emulate that behavior using the ToSocketAddr trait and Option but I am running into problems using them in conjunction.
This is a reduced example of what I am trying to do:
use std::io::net::ip::ToSocketAddr;
fn create_host<A: ToSocketAddr>(addr: Option<A>) {
match addr {
Some(a) => println!("Address is {}. Return a server host object.",a.to_socket_addr()),
None => println!("no address... Return a client.")
};
}
fn main() {
create_host(Some("localhost:12345"));
create_host(None);
}
The first call to create_host() works like a charm. The second call however will not compile.
Rustc returns
error: unable to infer enough type information about `_`; type annotations required
I am guessing that error is occurring because None doesn't provide any resolution to the generic A. I tried the following but this doesn't work either because ToSocketAddr does not implement the trait core::kinds::Sized.
fn create_host(addr: Option<ToSocketAddr>) {
...
}
Is there a way I can do this or do I need to take a different approach?
fn main() {
create_host(Some("localhost:12345"));
create_host(None::<&str>);
}
I've chosen &str here as it is the same type as on the first call, so that the compiler wouldn't generate another monomorphized version of the generic function. You could choose any type that implements ToSocketAddr.

Resources