How to make a type covariant?

Hey everyone,

I'm implementing a more compact version of std::vec::Vec and I'm running into an interesting compilation failure with one of the tests used for the real Vec.

Namely, I have a test failure here:

My IntoIter type is failing to be covariant!

I actually had this test passing before by having core::ptr::NonNull be a member of IntoIter but unfortunately, I was introducing UB by actually passing in a null pointer and my test suite was failing in release mode with an illegal instruction. (Good to know Rust actually optimizes around NonNull)

So now I've fixed the illegal instruction error but now my iterator type is failing to be covariant and I'm not sure how to convey to the compiler that this test should work.

Definition of IntoIter:

Let me know if any more information is required. Honestly, I'd rather live with the illegal instruction fix than having this iterator type be covariant but that's probably because I don't have a use-case where covariance matters for the iterator type yet.

Change *mut T to *const T.

So... this actually works.

But why?

Because *mut T is invariant and *const T is covariant. In fact, that's the only difference between them (besides functions that only take one or the other, but these are effectively just lints).

1 Like

Another answer to this "why" might be that you're not really using this *mut T for mutating data (and you shouldn't be, in fact). So, semantically, this is a constant pointer, not a mutable one.

Hmm, I have a follow up question.

One of the methods of IntoIter is as_mut_slice. Is it safe to cast a *const T to a *mut T for the purposes of making a mutable slice?

Namely, this guy:

Yes, as long as you originally got the raw pointer from a mutable reference, you are free to turn it back into one.