No, it returns KeyError. Or at least it should.
No, it returns KeyError. Or at least it should.
with match now being available, we even return explicit error objects and the ergonomics are pretty good (reminds me of rust).
The problem I see is there's no way to enforce the check that you actually handled/bubbled up the error. With exceptions, you just crash if you don't handle it, which is much preferred if determinism is the goal. Is there some way to use the type system to do this? Maybe incoming are UnhandledResult outgoing are some HandledResult or something like that?
I don't think Python has the equivalent of C++'s [[nodiscard]] or Rust's #[must_use], though, so if there are cases where the return value can legitimately be ignored then return values risk missing errors that would show up under exceptions.
# courses.py
def create(...) -> Course | ErrInvalid:
and they get used like match courses.create(...):
case courses.Course() as course:
# We use `course` below.
pass
case courses.ErrInvalid() as err:
# Error conditions are usually translated into early returns
raise fastapi.HTTPException(
status.HTTP_422_UNPROCESSABLE_ENTITY, err.message
)
return APICourseCreateResponse(id=course.id, ...)
It has worked (for us at least) pretty well to reduce the number of unhandled errors that make their way into Sentry. The granularity of the error types depends on the need (e.g., sometimes we just have an `ErrInvalid` that returns a message which gets displayed to the user, but sometimes we'll have ErrInvalidAddress or ErrInvalidTaxCode to be more specific for the context).And yeah, without nodiscard, we try™ to only do this on functions that return values that the caller will definitely need to use. Also combined with exhaustiveness checks on switch statements by default.
The standard answer is checked exceptions, which I'm on the fence about, but they don't seem to be very popular in any case. Python doesn't have them. C++ removed support for them which shows you how unpopular they were. Java has them and IIRC they were kind of ok to use in Android. Kotlin doesn't have them though so I guess the Java people didn't really like them either.
cache = {“key”: “value”, “some input”: None}
cache.get(“missing_key”)
Vs cache[“missing_key”]
There are better examples that could have been highlighted.Surely you meant _raises_? Or did you literally mean to return an exception class?