I’ve been playing with strict type checking and there is something I don’t fully understand.
Consider the following:
# mymeth() -> (Result | None)
aaa = derp.mymeth()
# get error: "some_prop" is not a known member of "None"
bbb = json.loads(aaa.some_prop)
return bbb
I can fix this by doing this:
if aaa:
bbb = json.loads(aaa.some_prop)
else:
raise(ValueError("mymeth() returned None, can't load as json"))
return bbb
But what am I getting out of this? Am I doing this right? It feels like I’m making more work for myself. If aaa
is None
then json.loads()
will raise itself and tell me that right? Or maybe that stack trace won’t be as readable to the user as my own more specific exception?
I’m sure this rule is useful, I’m just looking for an example of why and how I should be properly utilizing it.
We will see similar results from mypy, or
any other type checker.
Your complaint boils down to:
a stack trace will be produced one way or another in the None case, and one trace is as good as another.
This is mostly true,
and is an eloquent argument in favor of
using “low ceremony” untyped dynamic
python, as folks have been doing for
decades.
You are essentially saying “yeah,
I know, Bad Things can happen due to
de-referencing through a None,
but trust me, I have worked out the
details and I know which case
we’re handling here.”
That’s a perfectly legitimate approach.
The advantage of “linting clean”
with a type checker
is that the text of the source code
makes it clear that a None could
happen, and we have thought through that
case and appropriately handled it.
Source code is read far more often
than it is written.
We are making it easier for future
maintenance engineers to read and
understand what you wrote.
——-
The “if” you wrote is a perfectly nice
idiom. It leaves the code indented
a little.
Another common idiom for telling
the type checker “no None!” is
to simply “assert aaa”