Unitful.jl icon indicating copy to clipboard operation
Unitful.jl copied to clipboard

`AbstractQuantity` subtypes and quantity kinds

Open jariji opened this issue 2 years ago • 0 comments

The concept

"Defining ‘kind of quantity’" (Flater) and "On (kinds of) quantities" (Mari) discuss a hierarchy of kinds of quantity, in which radius and wavelength are both kinds of quantity that have dimension "length". I think this could be useful for a function that's supposed to take a radius but not a wavelength, or for just keeping track of what's what.

image

Implementation

Currently, for a type Q <: AbstractQuantity, the *(::Number, ::Q) and / methods return a Quantity, not a Q. I propose to replace them with methods that return a Q, so the type will be preserved. For example,

using Unitful
@eval Unitful begin
function *(x::Number, y::AbstractQuantity{T,D,U}) where {T,D,U}
    y isa AffineQuantity && throw(AffineError("an invalid operation was attempted with affine quantities: $x*$y"))
    Q = Base.typename(typeof(y)).wrapper
    v = x*y.val
    return Q{typeof(v), D, U}(v)
end
end
abstract type AbstractLength{T,D,U} <: Unitful.AbstractQuantity{T,D,U} end
abstract type AbstractRadius{T,D,U} <: AbstractLength{T,D,U} end
struct CircleRadius{T,D,U} <: AbstractRadius{T,D,U}
    val::T
end
cr = CircleRadius{Float64, Unitful.𝐋, Unitful.FreeUnits{(u"m",), Unitful.𝐋, nothing}}(3.0)
@assert (4 * cr) isa CircleRadius

Related work

The mp-units C++ library supports a bunch of kinds for dimesionless quantities. I haven't got my head all the way around this one yet.

Questions

There are a lot of different cases in quantities.jl, * / // fma etc. Which ones are supposed to propagate Q and which ones are supposed to promote to Quantity? I'm not sure. Maybe mp-units has the answer.

jariji avatar Jan 26 '24 01:01 jariji