Yes, there are lots of performance (type stability) reasons to use NaN!
The overhead with missing
can be more than an order of magnitude even in this simple example:
julia> x_nan = [([1., 2., 3.],), ([1., 2., 3., NaN],)]
julia> x_missing = [([1., 2., 3.],), ([1., 2., 3., missing],)]
julia> @btime map(x -> sum.(x), $x_nan)
35.578 ns (1 allocation: 80 bytes)
julia> @btime map(x -> sum.(x), $x_missing)
378.745 ns (8 allocations: 240 bytes)