mlx-swift
mlx-swift copied to clipboard
ErrorHandler in `withErrorHandler` should be marked as `throws`
I need to use withErrorHandler to avoid having my product crash with a fatalError when an error occurs in MLX. However, after using withErrorHandler, I found that I can only handle the error in the error handler and cannot throw the error to the caller. In my application scenario, I actually don't need to handle the error in the error handler, I want to rethrow the error to the caller instead.
Example:
func printHandler(_ message: String) throws {
throw MyCustomError(message)
}
let result = try withErrorHandler(printHandler) {
let a = MLXArray(0 ..< 10, [2, 5])
let b = MLXArray(0 ..< 15, [3, 5])
// this will trigger a broadcast error
return a + b
}
Yes, this is a limitation in what we have. There are two approaches: nothing (or most things) don't throw. If you use them wrong, it is a programmer error and it fails assertions / preconditions (fatal error). The second is to have everything throw that could throw. That includes operators like +.
Anyway, in swift you can't have a throw without a try and there is no try in your code. That said, I think you may actually want withError which turns the mlx/C++ exception into a swift exception -- it will throw out the top. You can also trigger them cooperatively in the same sort of way that tasks can check the cancel state.
So for example:
try withError {
let a = MLXArray(0 ..< 10, [2, 5])
let b = MLXArray(0 ..< 15, [3, 5])
// this will trigger a broadcast error
let x = a + b
return x
}
This will end up throwing an error when it returns -- this is the case I think you were going for. You can also write it like this:
try withError { error in
let a = MLXArray(0 ..< 10, [2, 5])
let b = MLXArray(0 ..< 15, [3, 5])
// this will trigger a broadcast error
let x = a + b
// explicitly check for errors or return from the block
try error.check()
return x
}
Differences:
- try withError { error in
- try error.check()
This example is too small for this to be very compelling, but you might imagine there is a bunch of work inside and you want to throw if an error has occurred -- you can do that with the try error.check(). This gives the try that is required for the throw.
Under the hood this is actually built on top of the one you referenced (withErrorHandler) -- it just stores the error away so that it can be delivered when asked for.
See if that works better!