`unsafeBitCast` vs `as!`

Can someone confirm to me if value as! SomeType means same as unsafeBitCast(value, to: SomeType.self)?

This example works, but is it guaranteed to always work in such scenario?

struct S<Something> {

  func foo() {
    let x: Something
    switch Something.self {
    case is Int.Type:
      x = unsafeBitCast(42, to: Something.self)
    default:
      fatalError()
    }
    bar(x)
  }

  func bar(_ x: Something) {
    print(x)
  }
}

let s = S<Int>()
s.foo() // prints 42

In my project I have only two types that will ever play the role as the generic parameter Something (there is also a constraint, but it's not shown in the example since it's not relevant) and the above switch is basically an emulation of an exhaustive switching over a sealed protocol.

1 Like

unsafeBitCast only cares that the types have the same size, if that's true, the cast should always succeed, with possible nastiness following if you've done a bad cast. Whereas as! will actually cause a crash if the cast is invalid.

class Super {
  let x: Int

  init(x: Int) {
    self.x = x
  }

  func doesSomething() -> Int {
    return x + 1
  }
}

class Child: Super {
  override func doesSomething() -> Int {
    return x + 2
  }
}

class OtherChild: Super {
  override func doesSomething() -> Int {
    return x + 3
  }

  func somethingCool() -> Double {
    return .pi
  }
}

let a: Super = Child(x: 50)

let b = a as! OtherChild // crash here immediately
let c = unsafeBitCast(a, to: OtherChild.self)

print(c.somethingCool()) // bad things here
1 Like

That makes sense if you don't dynamically check the type. What about unsafeBitCast if you check with is SomeType before trying to cast to that type? If there is any difference between it and as! then?

I'll fallback to as! in my case to be on the safe side.

AFAIU, unsafeBitCast is just about the ultimate way to break type safety, it won't do any validation other than a size check. Everything else is up to the programmer.

Also, because I'm not aware of many places in Swift that have specific control flow behavior. Definite initialization is one that comes to my mind.

1 Like

I'm not sure if this is just your sample or present in your real code, but FWIW if you're casting a numeric the unsafeBitCast doc exhorts you to use numericCast(_:).

as! does a lot more than unsafeBitCast; it knows how to change representations too. is acts the same way. I definitely wouldn't recommend using unsafeBitCast for this.

6 Likes