A big reason I came to Julia was to have physical units for scientific computations:
g = 4 * nS
,
E = 0 * mV
,
input_currents = g * (E .- V_mems)
.
All of the current solutions in Python are unfeasibly slow if you use them in simulations — they are really only for toy calculations. You can strip off units before passing your data to say Numba, and afterwards re-add them, but that’s just not worth the effort and code bloat. So: the promised land of Julia!
The de facto standard library in Julia is currently Unitful.jl: https://github.com/PainterQubits/Unitful.jl. I love how it handles units in the type system, yielding zero runtime overhead (that is, if your unitful arrays are of homogeneous dimension – which they often are). A perfect match with Julia.
Unitful seems to have learned from previous attempts at units in Julia. Such evolution in the ecosystem is lovely to see.
However, the interactive UX is pretty bad (and interactive use is a big reason for wanting physical units): Unitful quantities have massive type signatures, that make the display
of compound types unreadable.
(As an aside, compound types in Julia are already often quite unreadable… anyone know of a package that can display nested types a bit more humanely?).
A yet simple example:
julia> [(0:8)]
1-element Vector{UnitRange{Int64}}:
0:8
julia> using Unitful; using Unitful: mV
julia> [(0:8)*mV]
1-element Vector{StepRange{Quantity{Int64, 𝐋 ^2 𝐌 𝐈 ^-1 𝐓 ^-3, Unitful.FreeUnits{(mV,), 𝐋 ^2 𝐌 𝐈 ^-1 𝐓 ^-3, nothing}}, Quantity{Int64, 𝐋 ^2 𝐌 𝐈 ^-1 𝐓 ^-3, Unitful.FreeUnits{(mV,), 𝐋 ^2 𝐌 𝐈 ^-1 𝐓 ^-3, nothing}}}}:
(0:8) mV
– or try combining them with ComponentArrays
and DifferentialEquations
if not convinced.
For my own work I gave up on Unitful, and resorted to defining milli = 1e-3
; volt = 1
; mV = milli * volt
, as I also did in Python.
I think the verbosity problem in Unitful cannot be solved without a couple of quite breaking changes. Or we could have show(::Type{})
print something prettier, but then it would be lying about the actual type of the object, which isn’t desired.
Hence why I’m thinking of prototyping yet another units library, with leaner type parameters.
I wanted to get some others’ thoughts on this.
-
@ChrisRackauckas, I remember you having ideas of how a new unit library should work? – Especially with regards to Arrays of units.
(Unitful already handles this pretty nicely IMO: AnArray{Unitful.Quantity{Float64, ....}
has the exact same bits representation as the correspondentArray{Float64}
). -
Is there animo for a units interface package?
This would allow different ideas and tradeoffs in unit library design to coexist, while still allowing interop with downstream packages that processNumber
s (think e.g.Distributions.Normal(μ = 8 mV, σ = 2 mV)
: ok. But how do you specify the units of the variate for aLogNormal(μ, σ)
, whose parameters are unitless? You need a third argument – or maybe an extra type parameter – of typeAbstractUnits
).
Note that Base already hasoneunit(x)
. But you generally need more to support units: abstract types for Units and unitful Numbers; functions likeunits(x)
andstripunits(x)
; and objects likedimensionless
.
If such an interface package is deemed useful, it might live under a new github organization, sayJuliaUnits
.
(Tagging some contributors who might have thoughts: @ajkeller34 @sostock @giordano @tim.holy ).