Missing or NaN

What you describe as “no awareness” may, at least partially, just be a consequence of an overly complex and ad hoc design.

I taught a PhD-level course using R for years (before switching to Julia), and used it for about 15 years, but I am certain that there are corner cases of NA/NaN in R that would surprise me, and I would even find it difficult to locate them in the documentation ex post. Eg ?NA says

Numerical computations using ‘NA’ will normally result in ‘NA’

but a frequently discussed exception is

> NA^0
[1] 1

for which it is possible to concoct rationalizations, but I find it unexpected. Cf

julia> missing^0
missing

which is very clean semantics.

1 Like

I don’t understand how you use this. When is T filled in with a concrete type?

  • Lewis

You don’t have to filll it in with a concrete type, you could define:

using Missings
const M{T} = Union{Missing, T} where T <: Any
x = [1,2,3, missing]
eltype(x) == M{Int64}
> true

Maybe worth noting, that in v0.7/1.0 the Missings package is no longer needed. Missing support is built in. Example:

# Version 0.7.0-beta2.191 (2018-07-30 22:39 UTC)
julia> x = [1, 2, 3, missing]
4-element Array{Union{Missing, Int64},1}:
 1
 2
 3
  missing

julia> eltype(x)
Union{Missing, Int64}

julia> eltype.(x)
4-element Array{DataType,1}:
 Int64
 Int64
 Int64
 Any

Union{Missing,T} would be needed (here) to specify a non-standard element type (e.g. Int32 instead of Int64), and, maybe, in this case an alias like M{T} could be helpful:

julia> y = Array{Union{Int32, Missing}}([1, 2, 3, missing])
4-element Array{Union{Missing, Int32},1}:
 1
 2
 3
  missing

julia> M{T} = Union{Missing, T} where T
Union{Missing, T} where T

julia> z = Array{M{Int32}}([1, 2, 3, missing])
4-element Array{Union{Missing, Int32},1}:
 1
 2
 3
  missing

Not sure I would bother with M{T} though as it is not as obvious as Union{Missing, T}. Maybe I’m wrong, but with a T? syntax I could image that one could write: Array{Int32?}([1, 2, 3, missing]) in a future v1.x version?

1 Like

Thanks.

I am sure I don’t understand metaprogramming with Julia.

For example, the <: Any seems unnecessary. By not supplying a concrete or abstract type for T, T can stand for any type. Leaving out <: Any, I get the same type alias you created.

julia> using Missings

julia> const M{T} = Union{Missing, T} where T

Union{Missings.Missing, T} where T

Then, I also don’t understand what to do with this type. I can’t use it in an array constructor, for example:

julia> using Missings

julia> const M{T} = Union{Missing, T} where T <: Any

Union{Missings.Missing, T} where T

julia> b = Array{M{T},1}([1,2,3,missing])

*ERROR:* UndefVarError: T not defined

I note that in making a comparison to the type alias, I have to fill in T. it’s beginning to sink in, maybe, that a type declaration that references a type variable (T), is a little like a function in usage (but, otherwise not at all). The type variable is a parameter that has to be filled in. See at the end…

julia> using Missings

julia> const M{T} = Union{Missing, T} where T <: Any

Union{Missings.Missing, T} where T

julia> b = Array{M{T},1}([1,2,3,missing])

*ERROR:* UndefVarError: T not defined

julia> b = [1,2,3,missing]

4-element Array{Union{Int64, Missings.Missing},1}:

1

2

3

missing

julia> typeof(b)

Array{Union{Int64, Missings.Missing},1}

julia> eltype(b)

Union{Int64, Missings.Missing}

But, I can do this using the type alias when I fill in T with a concrete type:

julia> c = Array{M{Int64},1}([1,2,3, missing])

4-element Array{Union{Int64, Missings.Missing},1}:

1

2

3

missing

julia> d = Array{M{String},1}()

0-element Array{Union{Missings.Missing, String},1}

julia> push!(d, “foo”)

1-element Array{Union{Missings.Missing, String},1}:

“foo”

julia> push!(d, missing)

2-element Array{Union{Missings.Missing, String},1}:

“foo”

missing

I see this is the building block for a single type alias that can support all of the needed union types that a user could ever want. That simplifies things.

Still, I can’t escape the feeling that Julia is increasingly painting itself into the corner of a theoretical “demonstrator” language, a sort of ml for ML if you catch my drift. That’s certainly not the intent, and Julia works for pretty much all of what I previously did in Python, and with a lot more satisfaction.

In the future, you can ensure your code is more readable by quoting it with three backticks

``` 
julia> your code can go here
```

To clarify, this is not about metaprogramming. Metaprogramming is the process of inspecting expressions at compile time and altering them to change their behavior. Because types are first-class citizens in Julia, you can create aliases for them easily, but this is different than metaprogramming.

I add the where T <: Any at the end just because it makes the whole line more readable. Notice that T is essentially a variable that is defined for the scope of the expression where I define M{T}. T is defined as simply being any type, but outside of that code it has no meaning.

I use backticking in the discourse editor.

Let’s see if it works in email:


Sample code

Thanks for clarification on metaprogramming. To further clarify, the type variable needs to be filled in with a type expression when an actual type is being instantiated.