# Incorporate units into custom types

**URL:** <https://discourse.julialang.org/t/incorporate-units-into-custom-types/18539>\
**Category:** General Usage\
**Tags:** question\
**Created:** [December 10, 2018, 8:50pm UTC](https://discourse.julialang.org/t/incorporate-units-into-custom-types/18539 "2018-12-10T20:50:57Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [December 10, 2018, 8:50pm UTC](https://discourse.julialang.org/t/incorporate-units-into-custom-types/18539/1 "2018-12-10T20:50:57Z")

</div>

I have a package that works fine. First all my types and function were hard-coded to `Float64`. Then I evolved into parameterizing everything to `{T <: AbstractFloat}`. Now I’m looking into allowing for Unitful units, but I’m stumped on how to best do this.

It would be great if there was some _simple_ way of making everything unit-friendly while retaining the concreteness of the types/functions. **How do you people do it?**

As an example, here is how my Ray type looks like now:

```julia
using LinearAlgebra, StaticArrays

mutable struct Ray{T <: AbstractFloat}
    origin::SVector{3, T}
    direction::SVector{3, T}
    intensity::T
    Ray(o::SVector{3, T}, d::SVector{3, T}) where {T <: AbstractFloat} = new{T}(o, normalize(d), one(T))
end

```

While its origin can be unitful, its direction shouldn’t, and its intensity can remain unitless (though that too could get upgraded to a unitful representation).

```julia
julia> Ray(SVector(1.0, 2.0, 3.0), SVector(1.0, 2.0., 3.0))
Ray{Float64}([1.0, 2.0, 3.0], [0.267261, 0.534522, 0.801784], 1.0)

```

You can see how currently this won’t work with units:

```julia
julia> using Unitful

julia> import Unitful: μm

julia> Ray(SVector(1.0μm, 2.0μm, 3.0μm), SVector(1.0μm, 2.0μm, 3.0μm))
ERROR: MethodError: no method matching Ray(::SArray{Tuple{3},Quantity{Float64,Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)},Unitful.FreeUnits{(Unitful.Unit{:Meter,Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}}(-6, 1//1),),Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}}},1,3}, ::SArray{Tuple{3},Quantity{Float64,Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)},Unitful.FreeUnits{(Unitful.Unit{:Meter,Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}}(-6, 1//1),),Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}}},1,3})

```

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [December 10, 2018, 10:02pm UTC](https://discourse.julialang.org/t/incorporate-units-into-custom-types/18539/2 "2018-12-10T22:02:10Z")

</div>

This works:

```julia
using LinearAlgebra, StaticArrays
using Unitful: μm, unit

mutable struct Ray{T, S}
    origin::SVector{3, T}
    direction::SVector{3, S}
    intensity::T
end

Ray(o::SVector{3, T}, d::SVector{3, T}) where {T} = Ray(o, normalize(d), one(T)*unit(T))

Ray(SVector(1.0μm, 2.0μm, 3.0μm), SVector(1.0μm, 2.0μm, 3.0μm))

```

---

<div class="post-metadata">

**Author:** ![Daniel\_Berge](https://avatars.discourse-cdn.com/v4/letter/d/eb9ed0/32.png) [@Daniel\_Berge](https://discourse.julialang.org/u/Daniel_Berge)\
**Post date:** [December 10, 2018, 11:42pm UTC](https://discourse.julialang.org/t/incorporate-units-into-custom-types/18539/3 "2018-12-10T23:42:42Z")

</div>

You’d want to make the change to replace `one(T)*unit(T)` with `oneunit(t)` which is in `Base`.

```julia
using LinearAlgebra, StaticArrays
using Unitful
using Unitful: μm

mutable struct Ray{T, S}
    origin::SVector{3, T}
    direction::SVector{3, S}
    intensity::T
end
Ray(o::SVector{3, T}, d::SVector{3, T}) where {T} = Ray(o, normalize(d), oneunit(T))

```

I’d also point out there is a potential pitfall to assigning `Unitful` units. For instance, the rays `a` and `b` are equivalent, but the promotion will cause issues.

```julia
Ray(o::SVector{3},d::SVector{3}) = Ray(promote(o,d)...)

a=SVector(1.0μm, 2.0μm, 3.0μm)
b=SVector(1e-6u"m", 2e-6u"m", 3e-6u"m")

a==b #true
A=Ray(a,a)
B=Ray(a,b)

A==B #false
A.origin==B.origin #true
A.direction==B.direction #true
A.intensity==B.intensity #false intensity of 1μm ≠ 1m

```
