-
-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do not rollback errors #332
Comments
For a concrete example of what this would do: local badCode = scope:Computed(function()
error("Oh no")
end)
local foo = peek(badCode) --> Error in callback: Oh no (ID: callbackError) |
This would significantly reduce the use of |
A consideration here is that we need to be able to store information about the original location of the error, even if errors are now being thrown from a different location in the code base. Luckily Fusion has the |
This also ties into developer experience around lazy execution, specifically around how intuitive it is to throw errors at different points in the execution of the code. Under eager execution, errors in state objects are surfaced to users immediately after the change that causes the error. This is because the error is thrown as part of the update process, which is eager. However, under lazy execution, the update process may happen at a completely different point in time, detaching the error temporally from its cause in ways that are hard to predict by end users. So, instead of throwing the error from inside of the update process (which then has to be non-fatal because the update process is infallible), it's likely a better idea to throw the error when using an object in an invalid state instead. This makes the timing of errors predictable - if there's an error, it is always reliably on use. It also presents an opportunity to allow for intermediate error states without logging errors. Consider the following reasonable code: local items = scope:Value({"apple", "banana", "pear", "mango", "pomegranate"})
local index = scope:Value(4)
local currentItem = scope:Computed(function(use)
local item = use(items)[use(index)]
assert(item ~= nil, "Index is out of bounds")
return item
end)
items:set({"apple", "mango"})
index:set(2) This would log an The only time it's actually an error is when the intermediate value becomes visible to the outside world: -- ... snip ...
items:set({"apple", "mango"})
print("The current item is:", peek(currentItem)) -- This is not valid!
index:set(2) |
An important consequence of this change would be that Either errors would need to be caught inside the state objects, or the update process itself would need to be shielded from uncaught errors. |
I'm not sure how this will pan out, so here's my plan. I'm going to implement this but gate it behind an internal constant. I'll try having it switched on for a bit, but if it causes anyone any problems, it'll be easy to turn off again. |
Right now, if a
Computed
runs into an uncaught error, it falls back to returning the last valid value it was able to calculate. While this technically keeps the program running, it can very quickly lead to a domino effect of issues because in doing this, one of Fusion's core principles is violated.Fusion guarantees that, at any time, the reactive graph is completely internally consistent, and that - at least conceptually - calculations always see values sampled from the same point in time. The rollback behaviour violates this principle because it allows stale values and up-to-date values to mix in user code.
There's not a clean way of signalling an error has occurred in state object code, because the Luau types don't provision for returning error codes. While this could possibly be done, it would massively bloat almost all Fusion code with error checking - even infallible code - so I don't consider it to be a viable option.
So, as an alternative, I would propose that state objects should propagate uncaught errors to any other objects attempting to use them. From there, standard error catching mechanisms like
Safe
can be used to deal with the error.The text was updated successfully, but these errors were encountered: