Is 'as _' a bad practice?

Recently I've been using as _ a lot in my code (FFI/safe rust with triat object) and I personally think it's a very convenient and quick way to cast. But this is what I think, is this a bad practice or an awesome feature?

I would say it depends on what you're casting to.

4 Likes

I'm not a fan of as _, because it can do so many things, and thus you have to run inference in your head to figure out even in general what it's doing -- is it a pointer cast? a truncation? an unsizing? a widening? etc. And it's really easy for it to be wrong, because things like my_ptr as u8 are legal.

Using .into() for widening numeric casts and .cast() for pointer-to-pointer casts, though, are fine to have the type be inferred because they don't do so many things, and thus you can better understand what they're doing.

The language and library teams are working towards a future where we can start warning on certain uses of as, encouraging use of specific-intent library methods instead.

8 Likes

In particular, even just this week I had a length and ptr interface where I had used as _ and gotten the lengths and pointers confused. It's not sufficiently better than .cast() and .into() in those cases, and .as_ptr() as usize looks sufficiently weird to be obvious it's doing something weird.

I'm pretty sure cases like as *mut _ as *const _ is fine though.

3 Likes

I tend to specify the type there too because casting raw pointers can make UB really subtle and hidden.

1 Like

I was under the impression that as can only change one of pointer-ness, pointer const-ness or pointer target at a time, hence the need for two as in the first place? I could well be wrong though.

1 Like

Yes but you can for example &mut T as *const T and mutating that is UB (shouldn't be, but is).

1 Like

I'm confused, mutating what?

1 Like

The resulting pointer, i.e.:

let mut v = 0;
let v = &mut v as *const i32 as *mut i32;
unsafe {
    *v = 1;
}

Miri flags this as UB.

Right, but I was referring to needing to double cast to get from a mut ref to a const pointer, something I seem to keep running into. In any case, using * mut SomeLongTypeName instead of *mut _ isn't going to make that safer.