# Best way to handle variable types in function argument

**URL:** <https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719>\
**Category:** General Usage\
**Tags:** performance\
**Created:** [October 27, 2017, 1:25pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719 "2017-10-27T13:25:06Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Balinus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/balinus/32/243_2.png) [@Balinus](https://discourse.julialang.org/u/Balinus)\
**Post date:** [October 27, 2017, 1:25pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/1 "2017-10-27T13:25:06Z")

</div>

Hello!

In my work (Climate sciences) we often use [netCDF files](http://www.unidata.ucar.edu/software/netcdf/docs/netcdf_introduction.html). I’m wondering about the best way to handle the possible types in these files and how it affect the function that will use the extracted arrays inside those netCDF files.

The problem comes from the fact that the data inside the netCDF files can be either Float32 or Float64. My extraction function will fetch the data and put everything into [AxisArrays](https://github.com/JuliaArrays/AxisArrays.jl) (and then a custom type `ClimGrid` containing the metadata from the netCDF files). Hence, this means that the data inside the AxisArrays are sometimes Float32 and sometimes Float64, depending on the file.

My question is thus: what should I do for functions that are acting on the data? Should I create 2 functions, one with Float32 as argument and one with Float64 as the argument?

e.g.  
`foo(x::Float32)`  
`foo(x::Float64)`

Or perhaps should I just promote everything to Float64 (but this is costly, we are speaking about arrays of size `365 x 1068 x 510` for a single year of data and this can easily extends to 60-70 years.

I guess that there is an more easier answer involving “parametric” approach, but I must admit that I’m slightly lost with this approach.

Any hint or examples would be greatly appreciated!

---

<div class="post-metadata">

**Author:** ![Balinus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/balinus/32/243_2.png) [@Balinus](https://discourse.julialang.org/u/Balinus)\
**Post date:** [October 27, 2017, 1:35pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/2 "2017-10-27T13:35:39Z")

</div>

For reference, here’s the struct of `ClimGrid`, in case it helps understand the problem.

```julia
struct ClimGrid
  data::AxisArray
  model::String
  experiment::String
  run::String
  filename::String
  dataunits::String
  latunits::String
  lonunits::String
  var::String
end

```

Where `data::AxisArrays` can store either Float32 or Float64 data.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 27, 2017, 1:42pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/3 "2017-10-27T13:42:42Z")

</div>

First, you probably want to parameterize `ClimGrid` like:

```julia
struct ClimGrid{A <: AxisArray}
    data::A
    .
    .
end

```

As to the function, you can just use a signature like `foo(x::AbstractFloat)` to catch both `Float64` and `Float32` arguments. In Julia it is common to write generic functions that work on multiple types.

---

<div class="post-metadata">

**Author:** ![Balinus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/balinus/32/243_2.png) [@Balinus](https://discourse.julialang.org/u/Balinus)\
**Post date:** [October 27, 2017, 3:42pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/4 "2017-10-27T15:42:24Z")

</div>

Nice, thanks for your help! 🙂

I knew the answer would point towards some generic approach, but I couldn’t see how to do it correctly.

---

<div class="post-metadata">

**Author:** ![Balinus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/balinus/32/243_2.png) [@Balinus](https://discourse.julialang.org/u/Balinus)\
**Post date:** [October 27, 2017, 6:12pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/5 "2017-10-27T18:12:10Z")

</div>

Is there anything more I should modify if I use the struct declaration you provided? Because right now, I can no longer build ClimGrid struct. Here’s an example of errors I get

```julia
struct ClimGrid{A <: AxisArray}
    data::A
    .
    .
    function ClimGrid(data; model = "N/A", experiment = "N/A", run = "N/A", filename = "N/A", 
                                 dataunits = "N/A", latunits = "N/A", lonunits = "N/A", variable = "N/A", 
                                 typeofvar = "N/A", typeofcal = "N/A")

      new(data, model, experiment, run, filename, dataunits, latunits, lonunits, variable, typeofvar, 
           typeofcal)

    end
end

```

```julia
axisdata = AxisArray(data, Axis{:time}(d), Axis{:lon}(1:2), Axis{:lat}(1:2))
3-dimensional AxisArray{Float64,3,...} with axes:
    :time, 2003-01-01:1 day:2005-12-31
    :lon, 1:2
    :lat, 1:2
And data, a 1096×2×2 Array{Float64,3}:
[...]

C = ClimateTools.ClimGrid(axisdata, variable = "pr")
ERROR: MethodError: no method matching ClimateTools.ClimGrid(::AxisArrays.AxisArray{Float64,3,Array{Float64,3},Tuple{AxisArrays.Axis{:time,StepRange{Date,Base.Dates.Day}},AxisArrays.Axis{:lon,UnitRange{Int64}},AxisArrays.Axis{:lat,UnitRange{Int64}}}}; variable="pr")

```

I’m quite lost as I thought that replacing the initial struct to a parameterized struct would have no effect in the larger scheme of things. I guess it has to do with the type if the AxisArray `axisdata`, but I’m sure that we should not be so specific in the struct declaration (?).

```julia
julia> typeof(axisdata)
AxisArrays.AxisArray{Float64,3,Array{Float64,3},Tuple{AxisArrays.Axis{:time,StepRange{Date,Base.Dates.Day}},AxisArrays.Axis{:lon,UnitRange{Int64}},AxisArrays.Axis{:lat,UnitRange{Int64}}}}

```

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [October 27, 2017, 6:56pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/6 "2017-10-27T18:56:53Z")

</div>

I would just do

```julia
using AxisArrays
struct ClimGrid{A <: AxisArray}
    data::A
    model::String
    experiment::String
    # too lazy to add more fields
end

function ClimGrid(data; model = "N/A", experiment = "N/A")
    ClimGrid(data, model, experiment)
end

data = randn(3,2,2)
d = 1:3
axisdata = AxisArray(data, Axis{:time}(d), Axis{:lon}(1:2), Axis{:lat}(1:2))
ClimGrid(axisdata)

```

---

<div class="post-metadata">

**Author:** ![Balinus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/balinus/32/243_2.png) [@Balinus](https://discourse.julialang.org/u/Balinus)\
**Post date:** [October 27, 2017, 7:32pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/7 "2017-10-27T19:32:16Z")

</div>

Thanks! I see now where I made a mistake.

Somehow it works now that the function ClimGrid is outside the struct statement.

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [October 27, 2017, 7:46pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/8 "2017-10-27T19:46:46Z")

</div>

[Inner constructors](https://docs.julialang.org/en/stable/manual/constructors/#Inner-Constructor-Methods-1) for parametric types are a bit confusing. I would only use then, when you need them.

```julia
using AxisArrays

struct ClimGrid{A <: AxisArray}
    data::A
    model::String
    experiment::String
    # too lazy to add more fields
    function ClimGrid(data::A; model = "N/A", experiment = "N/A") where {A}
        new{A}(data, model, experiment)
    end
end

data = randn(3,2,2)
d = 1:3
axisdata = AxisArray(data, Axis{:time}(d), Axis{:lon}(1:2), Axis{:lat}(1:2))
ClimGrid(axisdata)

```

---

<div class="post-metadata">

**Author:** ![Balinus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/balinus/32/243_2.png) [@Balinus](https://discourse.julialang.org/u/Balinus)\
**Post date:** [October 27, 2017, 8:04pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/9 "2017-10-27T20:04:58Z")

</div>

Thanks for your help, my package is now much better and way less redundant! 🙂

---

<div class="post-metadata">

**Author:** ![Balinus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/balinus/32/243_2.png) [@Balinus](https://discourse.julialang.org/u/Balinus)\
**Post date:** [October 28, 2017, 2:04pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/10 "2017-10-28T14:04:20Z")

</div>

I’m wondering about the mechanics of Abstract types. For the function using AbstractFloat (`foo(x::AbstractFloat)`) or other Abstract like AbstractArray (been using `foo(x::AbstractArray{N, 2} where N` for 2D arrays where I don’t know if the array contains Float32 or Float64).

How does it work? The function compiles a Float32 and a Float64 version (at run-time)? This is my understanding from what I read in the documentation. Just wanted to know if I’m right.

Thanks!

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 28, 2017, 2:28pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/11 "2017-10-28T14:28:55Z")

</div>

> [@Balinus](#):
>
> The function compiles a Float32 and a Float64 version (at run-time)?

Yepp.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [October 28, 2017, 2:29pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/12 "2017-10-28T14:29:45Z")

</div>

> [@Balinus](#):
>
> How does it work? The function compiles a Float32 and a Float64 version (at run-time)? This is my understanding from what I read in the documentation. Just wanted to know if I’m right.

Yes. Here’s a post which is about handling types and dispatch which might clear things up.

> **[Type-Dispatch Design: Post Object-Oriented Programming for Julia - Stochastic...](http://www.stochasticlifestyle.com/type-dispatch-design-post-object-oriented-programming-julia/)**
>
> In this post I am going to try to explain in detail the type-dispatch design which is used in Julian software architectures. It’s modeled after the design of many different packages and Julia Base, and has been discussed in parts elsewhere. This is...

---

<div class="post-metadata">

**Author:** ![Balinus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/balinus/32/243_2.png) [@Balinus](https://discourse.julialang.org/u/Balinus)\
**Post date:** [October 28, 2017, 2:55pm UTC](https://discourse.julialang.org/t/best-way-to-handle-variable-types-in-function-argument/6719/13 "2017-10-28T14:55:18Z")

</div>

Thanks for the clarification!
