Rfcs: Move the 'static bound of Any to the methods.

Created on 6 Jan 2018  ·  5Comments  ·  Source: rust-lang/rfcs

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>.

T-libs breaking-change

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 ?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...

All 5 comments

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);
Was this page helpful?
0 / 5 - 0 ratings

Related issues

p-avital picture p-avital  ·  3Comments

3442853561 picture 3442853561  ·  3Comments

yongqli picture yongqli  ·  3Comments

3442853561 picture 3442853561  ·  4Comments

torkleyy picture torkleyy  ·  3Comments