# Why is this type unstable?

**URL:** <https://discourse.julialang.org/t/why-is-this-type-unstable/104124>\
**Category:** General Usage\
**Tags:** type-stability, ncdatasets\
**Created:** [September 21, 2023, 9:01pm UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124 "2023-09-21T21:01:51Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![yvikhlya](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yvikhlya/32/3753_2.png) [@yvikhlya](https://discourse.julialang.org/u/yvikhlya)\
**Post date:** [September 21, 2023, 9:01pm UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/1 "2023-09-21T21:01:51Z")

</div>

```julia
using Glob, NCDatasets

const colpath="path_to_data"

ncload(ds, ::Type{Array{T,N}}) where {T,N} = ds["T"][:,:,:,:]::Array{T,N}

function foo()
    files=glob("*.??????.nc4",colpath)
    
    NCDataset(files[1]) do ds
        ncv=ds["T"]
        nctype=eltype(ncv)
        ncdims=size(ncv)
        @show nctype ncdims
        ncload(ds,Array{nctype,length(ncdims)})
    end
end

```

```julia
@code_warntype foo()
MethodInstance for foo()
  from foo() @ Main ~/tmp/julia/foo.jl:7
Arguments
  #self#::Core.Const(foo)
Locals
  #10::var"#10#11"
  files::Vector{String}
Body::Array
1 ─ (files = Main.glob("*.??????.nc4", Main.colpath))
│ (#10 = %new(Main.:(var"#10#11")))
│ %3 = #10::Core.Const(var"#10#11"())
│ %4 = Base.getindex(files, 1)::String
│ %5 = Main.NCDataset(%3, %4)::Array
└── return %5

```

It knows that return value is Array, but does not know its dimensionality and element type, although by the time ncload is called, both nctype and ncdims are already defined. If I call ncload as

```julia
ncload(ds,Array{Union{Missing,Float32},4})

```

then `@code_warntype` shows that everything is type stable

```julia
@code_warntype foo()
MethodInstance for foo()
  from foo() @ Main ~/tmp/julia/foo.jl:7
Arguments
  #self#::Core.Const(foo)
Locals
  #12::var"#12#13"
  files::Vector{String}
Body::Array{Union{Missing, Float32}, 4}
1 ─ (files = Main.glob("*.??????.nc4", Main.colpath))
│ (#12 = %new(Main.:(var"#12#13")))
│ %3 = #12::Core.Const(var"#12#13"())
│ %4 = Base.getindex(files, 1)::String
│ %5 = Main.NCDataset(%3, %4)::Array{Union{Missing, Float32}, 4}
└── return %5

```

I want to be able to get the type and size of data from a dataset and pass them to ncload function and get a type stable result, which is efficiently allocated as a single chunk in memory. What I am doing wrong?

---

<div class="post-metadata">

**Author:** ![jecs](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jecs/32/1781_2.png) [@jecs](https://discourse.julialang.org/u/jecs)\
**Post date:** [September 21, 2023, 9:13pm UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/2 "2023-09-21T21:13:07Z")

</div>

My guess is that because `nctype` can be any type and `length(ncdims)` can be any integer `>= 0`, the compiler cannot guarantee a particular specialized Array type.

From the Performance Tips sections of NCDatasets.jl:

> Reading data from a file is not type-stable, because the type of the output of the read operation does depedent on the type defined in the NetCDF files and the value of various attribute (like `scale_factor`, `add_offset` and `units` for time conversion). All this information cannot be inferred from a static analysis of the source code. It is therefore recommended to use [type annotation](https://docs.julialang.org/en/v1/manual/types/index.html#Type-Declarations-1) if resulting type of a read operation in known:

---

<div class="post-metadata">

**Author:** ![yvikhlya](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yvikhlya/32/3753_2.png) [@yvikhlya](https://discourse.julialang.org/u/yvikhlya)\
**Post date:** [September 21, 2023, 9:48pm UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/3 "2023-09-21T21:48:21Z")

</div>

Yes, the only way to make things type stable is to harcode type annotations, which I do not want to do. But I don’t understand the difference between this

```julia
ncload(ds,Array{nctype,length(ncdims)})

```

and this

```julia
ncload(ds,Array{Union{Missing,Float32},4})

```

I am passing the same values to `ncload`. Should not compiler derive types from the values of arguments? Or does this mean that type stability of foo and type stability of ncload are different things?

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [September 21, 2023, 9:49pm UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/4 "2023-09-21T21:49:19Z")

</div>

For type stability, you have to be able to determine the type at compile time, before you know what is in the file.

---

<div class="post-metadata">

**Author:** ![yvikhlya](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yvikhlya/32/3753_2.png) [@yvikhlya](https://discourse.julialang.org/u/yvikhlya)\
**Post date:** [September 21, 2023, 9:54pm UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/5 "2023-09-21T21:54:08Z")

</div>

Looks like this can’t be avoided. If I am doing a computationally heavy analysis, how important would be to be type stable? Should I hard code data types each time, or just let compiler do with data what it wants?

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [September 21, 2023, 10:01pm UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/6 "2023-09-21T22:01:21Z")

</div>

Search for “Function Barrier” in the Julia docs (id link, but I’m on my phone.

---

<div class="post-metadata">

**Author:** ![yvikhlya](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yvikhlya/32/3753_2.png) [@yvikhlya](https://discourse.julialang.org/u/yvikhlya)\
**Post date:** [September 21, 2023, 10:03pm UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/7 "2023-09-21T22:03:15Z")

</div>

Yes, I’ve read about function barriers. I am trying to implement one. My concern is that whatever arrays I pass to function barrier should be continuously allocated in memory.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [September 21, 2023, 10:12pm UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/8 "2023-09-21T22:12:37Z")

</div>

The trick here is to manage type instability at the function call barrier.

Notice that `ncload` here is type stable after `foo` dynamically dispatches to it. The return type of `ncload` can be determined from the types of its arguments.

I would split my code into functions where I do not know the type and functions where I do know the type.

---

<div class="post-metadata">

**Author:** ![yvikhlya](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yvikhlya/32/3753_2.png) [@yvikhlya](https://discourse.julialang.org/u/yvikhlya)\
**Post date:** [September 21, 2023, 10:22pm UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/9 "2023-09-21T22:22:39Z")

</div>

So, if I do something like

```julia
data=NCDataset(file) do ds
        ds["T"][:,:,:,:] #this is type unstable anyway 
end

result=do_heavy_analysis_type_stable_function(data)

```

will I be ok in terms of performance? Or do I still need to do

```julia
data=NCDataset(file) do ds
        ds["T"][:,:,:,:]::Array{Union{Missing,Float32},4} # this is type stable
end

result=do_heavy_analysis_type_stable_function(data)

```

each time, if I really care about the performance?

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [September 21, 2023, 10:29pm UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/10 "2023-09-21T22:29:51Z")

</div>

The difference should be pretty negligible between the two but the first might be slightly faster. The difference is just the cost of writing an if statement.

---

<div class="post-metadata">

**Author:** ![Alexander-Barth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander-barth/32/3692_2.png) [@Alexander-Barth](https://discourse.julialang.org/u/Alexander-Barth)\
**Post date:** [September 22, 2023, 7:48am UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/11 "2023-09-22T07:48:03Z")

</div>

Indeed, I would just use the function barrier without cluttering the code with type annotations in most cases. I notice a formatting issue with NCDatasets documentation. I fixed this and expanded slightly this section:  
[https://alexander-barth.github.io/NCDatasets.jl/dev/performance/](https://alexander-barth.github.io/NCDatasets.jl/dev/performance/)

---

<div class="post-metadata">

**Author:** ![yvikhlya](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yvikhlya/32/3753_2.png) [@yvikhlya](https://discourse.julialang.org/u/yvikhlya)\
**Post date:** [September 22, 2023, 11:25am UTC](https://discourse.julialang.org/t/why-is-this-type-unstable/104124/12 "2023-09-22T11:25:31Z")

</div>

Thanks! This make things quite easy, since computational core is usually enclosed in some sort of function anyway. And thanks for fixing documentation!
