(The intent of this question is to improve my understanding of type stability, not criticize the language design.)
Most comparisons, like
false==1 and so on return a
Bool, but comparisons with
missing by design. This creates a gotcha in writing generic code with if statements, because for arbitrary input
a==b could be
Missing (and therefore
if a==b could be an error). Doesn’t this violate the principles of type stability?
Type stability means if the return type can predicted from the types of the arguments. No this does not violate type stability. If one the arguments are of type
Missing then you can predict the return type will be
To add on this, this is the conventional notion of type stability as a property of a method: given concrete types in, known return type out.
==(::Missing, ::Any) is type-stable because just given the first concrete
missing, it could only return
A looser notion of type stability applies to whether a variable or expression can be inferred to have a fixed concrete type at compile-time. When people are being precise, they say “inferable”/“has an inferable type” rather than “type-stable”, though it is accurate to say that the return type of a type-stable method is inferable.
I think the latter is what OP is getting at. If
a is known to be
missing, then the expression
a==b is known to be
missing. But if
a is not inferable because it could be
a==b is not inferable either and will dispatch to
== methods at run-time.
In other words, if I write code containing an instance of
a==b that could dispatch to either
==(::Any, ::Any) or
==(::Missing, ::Any) at runtime, then my code might be bad, but this doesn’t mean that the methods themselves are type unstable?
Yeah, that’s exactly right. If your code looks like:
if rand() < 0.5
x = "hello"
x = missing
if x == missing
then the type of
x can’t be concretely inferred, but it’s not