How does Default::default() work in rust? - rust

Just to clarify, I am not asking how to use the Default trait or how to implement it. What I am wondering is how a line like
let a: f32 = Default::default();
actually works? What is the implementation of Default::default()?
I would imagine something like this
fn default<T: Default>() -> T {
T::default()
}
I don't even really know what to search for since this seems to be an associated function to a Trait? Is this a thing? Anyways, I can't find it in the docs of std::default so I'm kind of stumped.

Default::default() is just <_ as Default>::default(), i.e. "use inference to find the type".

In this context, all of these lines are equivalent. Default is a trait implemented by f32 which contains the function fn default() -> Self. Essentially we are just telling the compiler that we want to invoke that trait. There might be other traits with a function default so this prevents ambiguity.
// Explicitly invoke the f32 implementation of Default.
let a: f32 = Default::default();
let a = <f32 as Default>::default();
// Call the function default for f32 which is resolved to be the trait Default.
let a = f32::default();
That being said, f32::default() would be preferred in almost all cases since it better expresses what you are trying to do. f32 does not provide a default function on its own and it would be strange if there was a competing trait imported to the module. If that were the case, <f32 as Default>::default() is better since it explicitly states which trait implementation of which type we are invoking the function default for. Lastly, Default::default() can be an easy alternative since it lets the compiler infer the type based on context, but is generally discouraged since it can make your code less verbose.

To add to #Locke's excellent answer, here's what the implementation of Default for f32 could look like:
impl Default for f32 {
fn default() -> Self { // Or f32 instead of Self, same thing.
0.0f32
}
}

Related

Conflicting trait implementations for types that clearly already implement the trait

I'm working with webassembly so I need to fetch the pointer to a buffer. In the case where T is just AsRef<[f32]> (that is, it can be converted to a slice if I'm understanding correctly), I have solved it like this:
#[derive(TS, Serialize)]
pub struct PtrBufF32(usize);
impl<T> From<T> for PtrBufF32
where T: AsRef<[f32]>
{
fn from(f32arr: T) -> Self {
let slc: &[f32] = f32arr.as_ref();
let ptr: *const f32 = slc.as_ptr();
Self(ptr as usize)
}
}
I had help from another stack overflow user to understand what's going on -- as far as I'm understanding, this means "for any T that can be converted to a refence of &[f32] (that is, a slice), then we can implement this trait. The result is simply the pointer to the start of the slice of course.
But then in addition to implementing for anything that can be represented as &[f32], we need to implement for any collection of things that can be represented by &[f32]. Like, if my type T implements Into<&[f32]>, then I can implement the type for any AsRef<[T]>, right? And so on. Any collection of those also implements it. So I thought:
impl<T> From<T> for PtrBufF32
where T: AsRef<[dyn Into<PtrBufF32>]>
{
fn from(f32arr: T) -> Self {
todo!()
}
}
But no… apparently those are "conflicting implementations" somehow?
error[E0119]: conflicting implementations of trait `std::convert::From<memory::ptrbuf::PtrBufF32>` for type `memory::ptrbuf::PtrBufF32`
Yet, if I try to PtrBufF32::from(vec![T]) and T implements Into<AsRef<[f32]>>, it doesn't let me. So clearly it's not conflicting, is it?
Thanks
As long as you implemented conversion for undefined list of types you should think a little bit more widely.
Imagine some type ForeignType, that implements both Into<PtrBufF32> and AsRef<[f32]>. Then if you call PtrBufF32::from(my_foreign_type), compiler cannot decide which of two implementation he must use.

What is a canonical approach for having lite concrete-specific behaviour in Rust? [duplicate]

How do I get Box<B> or &B or &Box<B> from the a variable in this code:
trait A {}
struct B;
impl A for B {}
fn main() {
let mut a: Box<dyn A> = Box::new(B);
let b = a as Box<B>;
}
This code returns an error:
error[E0605]: non-primitive cast: `std::boxed::Box<dyn A>` as `std::boxed::Box<B>`
--> src/main.rs:8:13
|
8 | let b = a as Box<B>;
| ^^^^^^^^^^^
|
= note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
There are two ways to do downcasting in Rust. The first is to use Any. Note that this only allows you to downcast to the exact, original concrete type. Like so:
use std::any::Any;
trait A {
fn as_any(&self) -> &dyn Any;
}
struct B;
impl A for B {
fn as_any(&self) -> &dyn Any {
self
}
}
fn main() {
let a: Box<dyn A> = Box::new(B);
// The indirection through `as_any` is because using `downcast_ref`
// on `Box<A>` *directly* only lets us downcast back to `&A` again.
// The method ensures we get an `Any` vtable that lets us downcast
// back to the original, concrete type.
let b: &B = match a.as_any().downcast_ref::<B>() {
Some(b) => b,
None => panic!("&a isn't a B!"),
};
}
The other way is to implement a method for each "target" on the base trait (in this case, A), and implement the casts for each desired target type.
Wait, why do we need as_any?
Even if you add Any as a requirement for A, it's still not going to work correctly. The first problem is that the A in Box<dyn A> will also implement Any... meaning that when you call downcast_ref, you'll actually be calling it on the object type A. Any can only downcast to the type it was invoked on, which in this case is A, so you'll only be able to cast back down to &dyn A which you already had.
But there's an implementation of Any for the underlying type in there somewhere, right? Well, yes, but you can't get at it. Rust doesn't allow you to "cross cast" from &dyn A to &dyn Any.
That is what as_any is for; because it's something only implemented on our "concrete" types, the compiler doesn't get confused as to which one it's supposed to invoke. Calling it on an &dyn A causes it to dynamically dispatch to the concrete implementation (again, in this case, B::as_any), which returns an &dyn Any using the implementation of Any for B, which is what we want.
Note that you can side-step this whole problem by just not using A at all. Specifically, the following will also work:
fn main() {
let a: Box<dyn Any> = Box::new(B);
let _: &B = match a.downcast_ref::<B>() {
Some(b) => b,
None => panic!("&a isn't a B!")
};
}
However, this precludes you from having any other methods; all you can do here is downcast to a concrete type.
As a final note of potential interest, the mopa crate allows you to combine the functionality of Any with a trait of your own.
It should be clear that the cast can fail if there is another type C implementing A and you try to cast Box<C> into a Box<B>. I don't know your situation, but to me it looks a lot like you are bringing techniques from other languages, like Java, into Rust. I've never encountered this kind of Problem in Rust -- maybe your code design could be improved to avoid this kind of cast.
If you want, you can "cast" pretty much anything with mem::transmute. Sadly, we will have a problem if we just want to cast Box<A> to Box<B> or &A to &B because a pointer to a trait is a fat-pointer that actually consists of two pointers: One to the actual object, one to the vptr. If we're casting it to a struct type, we can just ignore the vptr. Please remember that this solution is highly unsafe and pretty hacky -- I wouldn't use it in "real" code.
let (b, vptr): (Box<B>, *const ()) = unsafe { std::mem::transmute(a) };
EDIT: Screw that, it's even more unsafe than I thought. If you want to do it correctly this way you'd have to use std::raw::TraitObject. This is still unstable though. I don't think that this is of any use to OP; don't use it!
There are better alternatives in this very similar question: How to match trait implementors

Rust - downcast dyn trait [duplicate]

How do I get Box<B> or &B or &Box<B> from the a variable in this code:
trait A {}
struct B;
impl A for B {}
fn main() {
let mut a: Box<dyn A> = Box::new(B);
let b = a as Box<B>;
}
This code returns an error:
error[E0605]: non-primitive cast: `std::boxed::Box<dyn A>` as `std::boxed::Box<B>`
--> src/main.rs:8:13
|
8 | let b = a as Box<B>;
| ^^^^^^^^^^^
|
= note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
There are two ways to do downcasting in Rust. The first is to use Any. Note that this only allows you to downcast to the exact, original concrete type. Like so:
use std::any::Any;
trait A {
fn as_any(&self) -> &dyn Any;
}
struct B;
impl A for B {
fn as_any(&self) -> &dyn Any {
self
}
}
fn main() {
let a: Box<dyn A> = Box::new(B);
// The indirection through `as_any` is because using `downcast_ref`
// on `Box<A>` *directly* only lets us downcast back to `&A` again.
// The method ensures we get an `Any` vtable that lets us downcast
// back to the original, concrete type.
let b: &B = match a.as_any().downcast_ref::<B>() {
Some(b) => b,
None => panic!("&a isn't a B!"),
};
}
The other way is to implement a method for each "target" on the base trait (in this case, A), and implement the casts for each desired target type.
Wait, why do we need as_any?
Even if you add Any as a requirement for A, it's still not going to work correctly. The first problem is that the A in Box<dyn A> will also implement Any... meaning that when you call downcast_ref, you'll actually be calling it on the object type A. Any can only downcast to the type it was invoked on, which in this case is A, so you'll only be able to cast back down to &dyn A which you already had.
But there's an implementation of Any for the underlying type in there somewhere, right? Well, yes, but you can't get at it. Rust doesn't allow you to "cross cast" from &dyn A to &dyn Any.
That is what as_any is for; because it's something only implemented on our "concrete" types, the compiler doesn't get confused as to which one it's supposed to invoke. Calling it on an &dyn A causes it to dynamically dispatch to the concrete implementation (again, in this case, B::as_any), which returns an &dyn Any using the implementation of Any for B, which is what we want.
Note that you can side-step this whole problem by just not using A at all. Specifically, the following will also work:
fn main() {
let a: Box<dyn Any> = Box::new(B);
let _: &B = match a.downcast_ref::<B>() {
Some(b) => b,
None => panic!("&a isn't a B!")
};
}
However, this precludes you from having any other methods; all you can do here is downcast to a concrete type.
As a final note of potential interest, the mopa crate allows you to combine the functionality of Any with a trait of your own.
It should be clear that the cast can fail if there is another type C implementing A and you try to cast Box<C> into a Box<B>. I don't know your situation, but to me it looks a lot like you are bringing techniques from other languages, like Java, into Rust. I've never encountered this kind of Problem in Rust -- maybe your code design could be improved to avoid this kind of cast.
If you want, you can "cast" pretty much anything with mem::transmute. Sadly, we will have a problem if we just want to cast Box<A> to Box<B> or &A to &B because a pointer to a trait is a fat-pointer that actually consists of two pointers: One to the actual object, one to the vptr. If we're casting it to a struct type, we can just ignore the vptr. Please remember that this solution is highly unsafe and pretty hacky -- I wouldn't use it in "real" code.
let (b, vptr): (Box<B>, *const ()) = unsafe { std::mem::transmute(a) };
EDIT: Screw that, it's even more unsafe than I thought. If you want to do it correctly this way you'd have to use std::raw::TraitObject. This is still unstable though. I don't think that this is of any use to OP; don't use it!
There are better alternatives in this very similar question: How to match trait implementors

Is it idiomatic to use `impl<T> From<T> for Option<T>` in argument position?

This trait is implemented since 1.12.0:
impl<T> From<T> for Option<T> {
fn from(val: T) -> Option<T> {
Some(val)
}
}
How idiomatic is this as an argument? Consider this example:
fn do_things(parameters: &Foo, optional_argument: impl Into<Option<Duration>>) {
let optional_argument = optional_argument.into();
// use it...
}
If you see the documentation, it's (more or less) clear (if you know, that this trait is implemented). But if you see the code, you may be confused:
do_things(params, Duration::from_millis(100));
Is this fine to use or should it be avoided?
This pattern is uncommon, but reasonably easy to understand. If it's convenient in the context of your library's usage, it should be OK.
I think it's more common to have do_stuff and do_stuff_with_timeout functions.

Why doesn't String implement From<&String>?

Background
I know that in Rust people prefer &str rather than &String. But in some case we were only given &String.
One example is when you call std::iter::Iterator::peekable. The return value is a Peekable<I> object that wraps the original iterator into it and gives you one extra method peek.
The point here is that peek only gives you a reference to the iterator item. So if you have an iterator that contains Strings, you only have &String in this case. Of cause, you can easily use as_str to get a &str but in the code I will show below it is equivalent to a call to clone.
The question
This code
#[derive(Debug)]
struct MyStruct(String);
impl MyStruct {
fn new<T>(t: T) -> MyStruct
where
T: Into<String>,
{
MyStruct(t.into())
}
}
fn main() {
let s: String = "Hello world!".into();
let st: MyStruct = MyStruct::new(&s);
println!("{:?}", st);
}
doesn't compile because String doesn't implement From<&String>. This is not intuitive.
Why does this not work? Is it just a missing feature of the standard library or there are some other reasons that prevent the standard library from implementing it?
In the real code, I only have a reference to a String and I know to make it work I only need to call clone instead, but I want to know why.
To solve your problem, one could imagine adding a new generic impl to the standard library:
impl<'a, T: Clone> From<&'a T> for T { ... }
Or to make it more generic:
impl<B, O> From<B> for O where B: ToOwned<Owned=O> { ... }
However, there are two problems with doing that:
Specialization: the specialization feature that allows to overlapping trait-impls is still unstable. It turns out that designing specialization in a sound way is way more difficult than expected (mostly due to lifetimes).
Without it being stable, the Rust devs are very careful not to expose that feature somewhere in the standard library's public API. This doesn't mean that it isn't used at all in std! A famous example is the specialized ToString impl for str. It was introduced in this PR. As you can read in the PR's discussion, they only accepted it because it does not change the API (to_string() was already implemented for str).
However, it's different when we would add the generic impl above: it would change the API. Thus, it's not allowed in std yet.
core vs std: the traits From and Into are defined in the
core library, whereas Clone and ToOwned are defined in std. This means that we can't add a generic impl in core, because core doesn't know anything about std. But we also can't add the generic impl in std, because generic impls need to be in the same crate as the trait (it's a consequence of the orphan rules).
Thus, it would required some form of refactoring and moving around definitions (which may or may not be difficult) before able to add such a generic impl.
Note that adding
impl<'a> From<&'a String> for String { ... }
... works just fine. It doesn't require specialization and doesn't have problems with orphan rules. But of course, we wouldn't want to add a specific impl, when the generic impl would make sense.
(thanks to the lovely people on IRC for explaining stuff to me)
Since String does implement From<&str>, you can make a simple change:
fn main() {
let s: String = "Hello world!".into();
// Replace &s with s.as_str()
let st: MyStruct = MyStruct::new(s.as_str());
println!("{:?}", st);
}
All &Strings can be trivially converted into &str via as_str, which is why all APIs should prefer to use &str; it's a strict superset of accepting &String.

Resources