Had the same problem, for dimensionless quantities (relative dielectric function: epsilon, refractive index: n).

Unitful.jl seems overkill here (and does not work under 0.7 yet), since these quantities are basically complex numbers.

A single field struct is ugly.

It does not seem possible to subtype from a concrete type, as explained here.

So let’s define a primitive type such as

`primitive type Float_n <: AbstractFloat 64 end`

using `reinterpret`

as explained in https://stackoverflow.com/a/49582867/3565696

allows back and forth conversions between `Float64`

and the custom `Float_n`

.

```
# base Float type for refractive index n
primitive type Float_n <: AbstractFloat 64 end
Float_n(x::Float64) = reinterpret(Float_n, x)
# back to Float64
Float64(x::Float_n) = reinterpret(Float64, x)
# allow the REPL to show values of type Float_n
Base.show(io::IO, x::Float_n) = print(io, Float64(x))
# overload operators
Base.:+(x::Float_n, y::Float_n) = Float_n(Float64(x) + Float64(y))
Base.:-(x::Float_n, y::Float_n) = Float_n(Float64(x) - Float64(y))
Base.:*(x::Float_n, y::Float_n) = Float_n(Float64(x) * Float64(y))
Base.:/(x::Float_n, y::Float_n) = Float_n(Float64(x) / Float64(y))
# In my application it makes sense for mixed arguments operations to yield Float64
# it is always possible to explicitly reinterpret the result back to Float_n
Base.promote_rule(::Type{Float_n}, ::Type{Float64}) = Float64
julia> Float_n(1.0)
1.0
julia> typeof(ans)
Float_n
```

preliminary benchmarks look fine:

```
julia> using BenchmarkTools
julia> @btime Float_n(1.0) + Float_n(2.0)
0.014 ns (0 allocations: 0 bytes)
julia> @btime 1.0 + 2.0
0.014 ns (0 allocations: 0 bytes)
@btime Float_n(1.0) + 2.0
0.014 ns (0 allocations: 0 bytes)
```

This is not perfect:

```
julia> a = rand(Float_n, 10000);
ERROR: ArgumentError: Sampler for this object is not defined
```

It would be nice for `Float_n`

to work as `Float64`

when a method does not match.