Open ibraheemdev opened 3 years ago
Should these be added to std::error::Error
too?
I don't see how that would be useful. You generally don't know the concrete type of an error before downcasting.
This would allow me to shed my dependency on unsafe_any
. What's the state of this feature? Is it ready for an FCP?
Now that {Option, Result}::unwrap_unchecked
are stabilized, I wonder if there is much benefit to these methods.
Instead of downcast_unchecked
, is there a good reason to not just have the more general
impl Box<T: ?Sized, A> {
pub unsafe fn cast_unchecked<U>(self) -> Box<U, A> {
debug_assert_eq!(Layout::for_value(&*self), Layout::new::<U>());
unsafe {
let (raw, alloc) = Box::into_raw_with_allocator(self);
Box::from_raw_in(raw.cast(), alloc)
}
}
}
? I suppose you lose the debug_assert!
for correct typing which is possible if you have dyn Any
, though it is true that you can already any.downcast().unwrap_unchecked()
for that.
To immediately answer my own question: Box
doesn't want to add methods to arbitrary types like that. cast_unchecked
is still useful but would probably instead be pub unsafe fn Box::<T: ?Sized, A>::cast<U>(this: Self) -> Box<U, A>
to make it an associated function rather than a method which could shadow a pointee's method.
@ibraheemdev this still generates better code than downcast_ref().unwrap_unchecked()
.
pub fn cast(a: &dyn std::any::Any) -> &i32 {
unsafe { a.downcast_ref_unchecked() }
}
compiles to
example::cast:
mov rax, rdi
ret
whereas
pub fn cast(a: &dyn std::any::Any) -> &i32 {
unsafe { a.downcast_ref().unwrap_unchecked() }
}
becomes
example::xx:
push rbx
mov rbx, rdi
call qword ptr [rsi + 24]
mov rax, rbx
pop rbx
ret
Both compiled with opt-level=3
I think llvm didn't realize that T::type_id
call is pure (because it's called through the vtable?), so it kept the call.
huh, why is type_id not stored directly in the vtable?
huh, why is type_id not stored directly in the vtable?
The short version is that Rust doesn't have a way to get associated constant data from a trait object (yet).
The semantics of a.downcast_ref_unchecked()
and a.downcast_ref().unwrap_unchecked()
are still different. For example, with a.downcast_ref_unchecked()
one could "transmute" between two types that are different but #[repr(C)]
compatible in layout, whereas with a.downcast_ref().unwrap_unchecked()
you'd likely be dereferencing a null pointer.
I'd like to point out that in all other places in the std, the ref
/mut
part comes after the unchecked
part. Therefore this should be downcast_unchecked_ref
and downcast_unchecked_mut
to stay concistent AFAICS.
Hey, is there a reason that Box::downcast
and similar functions require T
to be sized? AFAICT they should work with unsized types.
@Wasabi375 It's not possible to unsize an unsized type, so it's equally not possible to downcast to an unsized type, because the source is already unsized. If you want to do something like that you need a double indirection.
I think I might have found a bug with with type inference or something that confused me, because it claimed that I couldn't call downcast_unchecked
because dyn Any
is not sized. But when I specify the type directly the error goes away. I'll try to create a simple example and file a proper bug report. (#127005)
I was curious if the code quality generated by unwrap_unchecked
vs downcast_ref_unchecked
had improved at all.
It seems it has.
https://rust.godbolt.org/z/77E7an7f1
Note that it seems to be condensing both functions to one since they're end product is identical. You can comment out the first one to explicitly see that the second one is equivalent.
Feature gate:
#![feature(downcast_unchecked)]
This is a tracking issue for the
downcast_unchecked
,downcast_ref_unchecked
, anddowncast_mut_unchecked
methods.Public API
Steps / History
Unresolved Questions