Given a struct, a class, and typed closure:
struct Vector3d {
var X:Double
var Y:Double
var Z:Double
}
class Sprite {
var mass: Double = 0.0
init(mass: Double) {
self.mass = mass
}
}
typealias ForceComputation =
(NSTimeInterval, Sprite) -> Vector3d?
The following code crashes with EXC_BAD_INSTRUCTION
:
// Construct an instance of the class to call back with
var ball = Sprite(mass: 3.0)
// Create an instance of closure
var gravity:ForceComputation = { (projectile:Sprite) -> Vector3d in
// use this line to close ball so it's available in debugger
var mass1 = ball.mass
// use mass1 in following line to ensure not optimized out
// (ignore invalid gravity formula)
var verticleAcceleration = -9.8 * projectile.mass * mass1
return Vector3d(X:0.0, Y:verticleAcceleration, Z:0.0)
}
// activate the closure
gravity(ball)
The debugger shows two different values for projectile
and ball
. The field mass
in projectile
is invalid. However mass
is valid for ball
both inside and outside the closure. There are no compiler errors or warnings but EXC_BAD_INSTRUCTION
is thrown when projectile.mass
is executed?
Despite the misleading debug data, the problem has nothing to do with the parameter to the ForceComputation
closure. The problem is the returned struct is defined as optional in the typealias
:
typealias ForceComputation =
(Sprite) -> Vector3d?
but constructed with a non-optional return type (note the lack of a ?
after Vector3d
):
// Create an instance of closure
var gravity:ForceComputation = { (projectile:Sprite) -> Vector3d in
....
}
Changing the above code to remove the typing:
// Create an instance of closure
var gravity = { (projectile:Sprite) -> Vector3d in
....
}
will fix the code or ensuring that the return type is optional (note ?
after Vector3d
):
// Create an instance of closure
var gravity:ForceComputation = { (projectile:Sprite) -> Vector3d? in
....
}
will also make this work. My question is if this is a compiler bug and should be reported to Apple or is there a reason the EXC_BAD_INSTRUCTION
throwing code should compile?
This is a compiler bug (confirmed via Twitter here) but there are already a number of known issues around optional-ness to returns with Swift.