Stream: general

Topic: Coerce trait object to another


gnzlbg (Dec 02 2019 at 13:15, on Zulip):

Is there a simple way to coerce one trait object to another? e.g.

let x: &dyn Debug = &[1, 2, 3] as &[_];

?

simulacrum (Dec 02 2019 at 13:16, on Zulip):

you only have one trait object here?

gnzlbg (Dec 02 2019 at 13:17, on Zulip):

yes

gnzlbg (Dec 02 2019 at 13:18, on Zulip):
let a = &[1, 2, 3] as &[_];
let b: &dyn Debug = a;

works

simulacrum (Dec 02 2019 at 13:18, on Zulip):

so I don't really understand what you're asking

simulacrum (Dec 02 2019 at 13:18, on Zulip):

the as &[_] isn't doing anything there

simulacrum (Dec 02 2019 at 13:18, on Zulip):

(indeed I'm somewhat surprised that compiles)

simulacrum (Dec 02 2019 at 13:18, on Zulip):

let v: &dyn std::fmt::Debug = &[0, 2, 3]; just works

gnzlbg (Dec 02 2019 at 13:20, on Zulip):

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=15d52f7f88a06a34c752da1a55fbbae8

gnzlbg (Dec 02 2019 at 13:20, on Zulip):

The &[_] coerces a &[T; N] into a &[T]

simulacrum (Dec 02 2019 at 13:21, on Zulip):

hm, right

simulacrum (Dec 02 2019 at 13:21, on Zulip):

yeah, you can't do this

simulacrum (Dec 02 2019 at 13:21, on Zulip):

since we can't inherit from a vtable

gnzlbg (Dec 02 2019 at 13:22, on Zulip):

what do you mean with "inherit" ?

gnzlbg (Dec 02 2019 at 13:22, on Zulip):

Slices do implement Debug right ?

simulacrum (Dec 02 2019 at 13:22, on Zulip):

well, okay, I should say that differently

simulacrum (Dec 02 2019 at 13:22, on Zulip):

basically &[T] is not sized, so &dyn fmt::Debug has nowhere to 'put' the pointer to self

simulacrum (Dec 02 2019 at 13:23, on Zulip):

(since trait objects are always 2 ptrs today)

gnzlbg (Dec 02 2019 at 13:23, on Zulip):

where is the vtable of <&[T] as Debug> ?

gnzlbg (Dec 02 2019 at 13:24, on Zulip):

ahh i think i see the problem

simulacrum (Dec 02 2019 at 13:24, on Zulip):

where? The vtable exists and you can do that

simulacrum (Dec 02 2019 at 13:24, on Zulip):

but you can't "fit" it into &dyn fmt::Debug

gnzlbg (Dec 02 2019 at 13:24, on Zulip):

So we can point the vtable pointer of dyn fm::Debug to the vtable

simulacrum (Dec 02 2019 at 13:25, on Zulip):

yes, that works (and is indeed always the case)

gnzlbg (Dec 02 2019 at 13:25, on Zulip):

the problem is the self pointer

gnzlbg (Dec 02 2019 at 13:25, on Zulip):

damn,

simulacrum (Dec 02 2019 at 13:25, on Zulip):

but then you only have one pointer left for the self pointer, and you need two

simulacrum (Dec 02 2019 at 13:25, on Zulip):

but if you need to do this and the lifetimes work out, let _x: &dyn std::fmt::Debug = &a; would work

gnzlbg (Dec 02 2019 at 13:25, on Zulip):

one needs two because &[T] is a fat pointer, not a thin one

gnzlbg (Dec 02 2019 at 13:26, on Zulip):

e.g. if &[T] was a thin pointer to [len, padding, [elements: T, T, T, ...]]

gnzlbg (Dec 02 2019 at 13:26, on Zulip):

it would work

gnzlbg (Dec 02 2019 at 13:26, on Zulip):

but then you can't have subslices

simulacrum (Dec 02 2019 at 13:26, on Zulip):

correct

gnzlbg (Dec 02 2019 at 13:27, on Zulip):

damn

gnzlbg (Dec 02 2019 at 13:27, on Zulip):

there is no good solution to this

simulacrum (Dec 02 2019 at 13:27, on Zulip):

well, I mean, it depends on your use case

simulacrum (Dec 02 2019 at 13:27, on Zulip):

you can manually make the bigger vtable

gnzlbg (Dec 02 2019 at 13:27, on Zulip):

So I have a big array, that doesn't have a Debug impl

gnzlbg (Dec 02 2019 at 13:27, on Zulip):

I need to pass it to an API that takes &dyn Debug

gnzlbg (Dec 02 2019 at 13:28, on Zulip):

and I thought I could be smarter by just coercing it to a slice

simulacrum (Dec 02 2019 at 13:28, on Zulip):

oh that you can definitely do

simulacrum (Dec 02 2019 at 13:28, on Zulip):

just do &&[...]`

simulacrum (Dec 02 2019 at 13:28, on Zulip):

because &&[u32] is not fat

simulacrum (Dec 02 2019 at 13:29, on Zulip):

@gnzlbg does that work for you?

gnzlbg (Dec 02 2019 at 13:29, on Zulip):

yeah

gnzlbg (Dec 02 2019 at 13:30, on Zulip):
let a = [0; 128];
let b: &dyn Debug = &&a[..];
gnzlbg (Dec 02 2019 at 13:30, on Zulip):

that works

simulacrum (Dec 02 2019 at 13:30, on Zulip):

note that the type there is &'a (dyn Debug + 'b) I believe, not + 'static like normally

simulacrum (Dec 02 2019 at 13:31, on Zulip):

but for the most part you probably don't care

gnzlbg (Dec 02 2019 at 13:31, on Zulip):

Is there an impl of Debug for &T where T: Debug ?

gnzlbg (Dec 02 2019 at 13:31, on Zulip):

or how does that work internally ?

simulacrum (Dec 02 2019 at 13:31, on Zulip):

hm, perhaps?

simulacrum (Dec 02 2019 at 13:31, on Zulip):

rustdoc says yes

simulacrum (Dec 02 2019 at 13:31, on Zulip):

and for &mut T

gnzlbg (Dec 02 2019 at 13:31, on Zulip):

so that makes sense

gnzlbg (Dec 02 2019 at 13:32, on Zulip):

thanks

gnzlbg (Dec 02 2019 at 13:32, on Zulip):

so i wonder if this works, why can't the initial coercion work ?

gnzlbg (Dec 02 2019 at 13:32, on Zulip):

like the pointer to self would be a pointer to the slice object

simulacrum (Dec 02 2019 at 13:33, on Zulip):

because we don't double coerce or so

simulacrum (Dec 02 2019 at 13:33, on Zulip):

i.e., you've not given that pointer, so we won't make it ourselves

gnzlbg (Dec 02 2019 at 13:33, on Zulip):

but we do that when creating a slice

simulacrum (Dec 02 2019 at 13:34, on Zulip):

hm, how so?

gnzlbg (Dec 02 2019 at 13:34, on Zulip):

e.g. when doing &[T; N] as &[T] we create the slice trait object, with a pointer, and a length - notice that the length did not exist in memory anywhere, since is part of the type

simulacrum (Dec 02 2019 at 13:34, on Zulip):

the length is the vtable bit though

simulacrum (Dec 02 2019 at 13:34, on Zulip):

which is always synthesized out of "nowhere"

simulacrum (Dec 02 2019 at 13:34, on Zulip):

the pointer is "constant"

gnzlbg (Dec 02 2019 at 13:35, on Zulip):

ah, wait, by double-coerce you mean that we don't create pointers out of nowhere ?

gnzlbg (Dec 02 2019 at 13:36, on Zulip):

e.g. for &[T; N] as &[T] as &dyn Debug we'd need to create a pointer to the &[T] and coerce that pointer to &dyn Debug

simulacrum (Dec 02 2019 at 13:36, on Zulip):

yes

gnzlbg (Dec 02 2019 at 13:36, on Zulip):

so this works: &(&[T; N] as &[T]) as &dyn Debug because we don't have to create any pointers for that

gnzlbg (Dec 02 2019 at 13:36, on Zulip):

(the user created it)

simulacrum (Dec 02 2019 at 13:36, on Zulip):

that's my understanding, yeah

gnzlbg (Dec 02 2019 at 13:37, on Zulip):

thanks, i think i've got this

csmoe (Dec 02 2019 at 18:59, on Zulip):

basically &[T] is not sized, so &dyn fmt::Debug has nowhere to 'put' the pointer to self

@simulacrum did you mean [T] is not sized? I used to think &[T]is sized, am I wrong? :fear:

simulacrum (Dec 02 2019 at 18:59, on Zulip):

er, s/sized/thin

RalfJ (Dec 03 2019 at 15:37, on Zulip):
let a = &[1, 2, 3] as &[_];
let b: &dyn Debug = a;

works

@gnzlbg I was very surprised that it should work and when I tried it didn't... is there a typo here?

gnzlbg (Dec 03 2019 at 15:38, on Zulip):

I think so

gnzlbg (Dec 03 2019 at 15:39, on Zulip):

I might have had a typo in my playground, this works: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e830ca21ef05fcccba30958d2da231bb

gnzlbg (Dec 03 2019 at 15:39, on Zulip):

but that works due to the Debug impl for small arrays

gnzlbg (Dec 03 2019 at 15:40, on Zulip):

this doesn't work: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=fa83c860d4092b312eb0e2af615cc1b1

Last update: Dec 12 2019 at 01:10UTC