Skip to content

Consistent error APIs #536

Open
Open
@Bromeon

Description

@Bromeon

There are several places in gdext where things can go wrong. At the moment, there is no unified guideline on how to design such APIs.

Logic vs runtime error

Traditionally, errors can be split into logic errors (bugs that must be fixed) and runtime errors (that need to be expected and handled by the developer). However, this is not a very clear-cut line, since the scene tree or other invariants are technically known at compile time, but can still fail.

For example, try_load::<T>("path/to/Node") can fail for wrong paths or wrong types. This may be a logic error (assuming the developer should know their scene tree) or a runtime error (if tree is created dynamically, e.g. in a level editor). As such, I'm not sure if strict split of logic/runtime is that useful here.

Coarse vs. fine

To me, first priority is that there is a descriptive error message. If something goes wrong, the developer should have a way to know this from the error message, ideally with some context.

Then, there has been the discussion about mapping each internal error to a public enumerator. That would mean most APIs have their own domain-specific error types. But how do we design those, if they have more fine-grained "internal" causes that may not be relevant for the public API?

I would like the design be driven by actual use cases and not theoreticals. Yes, it's possible to expose all information that gdext possesses about an error to the user, but it's also costly and impractical, in terms of maintenance, discoverability, good abstraction boundary, UX. So each symbol that is exposed must have a clear use case.

Integration with Godot

There is currently engine::global::Error which is returned from some engine APIs. We also have domain-specific errors about failed calls, etc. Ideally we can integrate them into our error API design.

Compatibility

Having very fine-grained error enums comes at a cost, even with #[non_exhaustive]. It makes it harder to refactor things, smaller changes often become breaking. For example, changing an error enum from unit (C-style enumerator) to struct style (having fields).

Compatibility also conflicts with fine-grainedness. Once we have crates.io releases and take SemVer seriously, we cannot easily break these things without waiting for the next release, and it's not great if error types are expressing the wrong thing due to technical limitations (like adding a field that would interfere with existing code).

Self-containedness

I don't want to add crates like thiserror or anyhow to gdext. But maybe we can design errors in a way that they are extensible and composable with these crates.

Metadata

Metadata

Assignees

No one assigned

    Labels

    c: coreCore componentsfeatureAdds functionality to the library

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions