In principle the trait Any works just like a 'top type' trait. However there's the unnecessary bound of 'static involved by the restrictions of downcast method. So i propose that the 'static bound move to the methods, so Any can act as a real 'top type' trait.
Use case: When i want to erase the type of a value and just make sure it is alive until a certain point, currently there's no good way to do so. However, with the changes above, i can just put it into a Box<Any + 'a>.
This is a breaking change.
I think anything like this requires ATC tricks according to https://github.com/rust-lang/rfcs/pull/1849
Use case: When i want to erase the type of a value and just make sure it is alive until a certain point, currently there's no good way to do so. However, with the changes above, i can just put it into a
Box<Any + 'a>.
Is there anything wrong with the two line replacement
pub trait MyAny { }
impl<T: ?Sized> MyAny for T { }
(I mean, other than the obvious it's not in the standard lib?)
@ExpHP yes, it's enough for the use case. However for it to act as a 'top type' here, if there're more ?Trait coming up, i guess the impl has to be changed to pick up all of those negative reasoning bounds. I don't think it can be well maintained within user land, since different rustc version might have a different list...
This would help with Error trait. While Any cannot be feasibly changed (it would be a breaking change), there is an option of deprecating Any and creating a new trait. With a hypothetical name of Unknown (although I'm pretty sure there is a better name, maybe referring to RTTI provided by a trait), there could be an implementation like this.
use std::any::TypeId;
use std::fmt;
pub trait Unknown {
fn type_id(&self) -> TypeId
where
Self: 'static;
}
impl<T: ?Sized> Unknown for T {
fn type_id(&self) -> TypeId
where
T: 'static,
{
TypeId::of::<T>()
}
}
macro_rules! imp {
($bound:ty) => {
// Not providing `+ '_` to possibly allow TypeId debug information
impl fmt::Debug for $bound {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Unknown")
}
}
impl $bound {
pub fn is<T: 'static>(&self) -> bool {
let t = TypeId::of::<T>();
let concrete = self.type_id();
t == concrete
}
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
if self.is::<T>() {
unsafe { Some(&*(self as *const dyn Unknown as *const T)) }
} else {
None
}
}
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe { Some(&mut *(self as *mut dyn Unknown as *mut T)) }
} else {
None
}
}
}
};
}
imp!(dyn Unknown);
imp!(dyn Unknown + Send);
imp!(dyn Unknown + Send + Sync);
Most helpful comment
@ExpHP yes, it's enough for the use case. However for it to act as a 'top type' here, if there're more
?Traitcoming up, i guess the impl has to be changed to pick up all of those negative reasoning bounds. I don't think it can be well maintained within user land, since different rustc version might have a different list...