Unitful dispatch

Why this works:

julia> function hz(x::typeof(1.0u"Hz"))
       2x
       end
hz (generic function with 1 method)

and this does not work:

julia> typeof(1.0u"Hz")
Quantity{Float64,𝐓^-1,Unitful.FreeUnits{(Hz,),𝐓^-1,nothing}}

julia> function hz2(x::Quantity{Float64,𝐓^-1,Unitful.FreeUnits{(Hz,),𝐓^-1,nothing}})
       4x
       end
ERROR: UndefVarError: 𝐓 not defined
Stacktrace:
 [1] top-level scope at REPL[37]:1

Just guessing, but maybe you need import Unitful: 𝐓?

3 Likes

Yes,

import Unitful: 𝐓,Hz

solves the problem.
Thanks!

A followup:

julia> function hz(x::typeof(1.0Hz))
       2x
       end
hz (generic function with 1 method)

julia> hz(2.0Hz)
4.0 Hz

julia> hz(1/0.5s)
ERROR: MethodError: no method matching hz(::Quantity{Float64,𝐓^-1,Unitful.FreeUnits{(s^-1,),𝐓^-1,nothing}})
Closest candidates are:
  hz(::Quantity{Float64,𝐓^-1,Unitful.FreeUnits{(Hz,),𝐓^-1,nothing}}) at REPL[68]:1
Stacktrace:
 [1] top-level scope at REPL[70]:1

However

julia> 2.0Hz + 1/0.5s 
4.0 s^-1

works?? Why?

How to define a type for dispatch that will accept either Hz or 1/s, Union?

The real question is why do you have to do this? Its better if we can help you find a solution to your problem generally than specifically help on this one detail.

1 Like

Sorry, I thought it is obvious. I want to write a function that (in this case) accepts frequency as an argument and dispatch using it. Frequency can be defined as Hertz or 1/s (an inverse of period). Computationally these units are identical. How to accomplish this? Maybe I have misunderstood the purpose of Unitful.

1 Like

I haven’t used Unitful, but I’m guessing that Hz and typeof(1/0.5s) are different. In that case you have to define your function to accept a Union or define a wrapper to convert from inverse seconds to Hz. But because arithmetic operations are common, Unitful has evidently defined promotion rules to automatically convert types as needed in arithmetic operations.

1 Like

What I’m wondering is why do you want to do that! What is this for? Why dispatch on the units?

You will get more helpful answers if you add some context about the real world problem that dispatching on frequency provides a solution to.

1 Like

Just don’t specify the units you want, instead specify the dimensions. E.g. in this case, you want any Quantity which has dimensions of 𝐓^-1, so you just do

julia> using Unitful; using Unitful: Hz, s, 𝐓

julia> f(x::Quantity{<:Any, 𝐓^-1}) = 2x
f (generic function with 1 method)

julia> f(2.0Hz)
4.0 Hz

julia> f(1/0.5s)
4.0 s^-1
5 Likes

I am writing an averaging function for interferometric data. It is possible to average over time or frequency and the algorithm is different for these -> dispatch. BTW, I am using DimensionalData.jl for dealing with multidimensional data (in this case polarization, IF band, frequency channel and time), makes everything a lot easier, thanks!

1 Like

This is exactly what I was looking for (and expands to many other cases), many thanks!

There are already build-in names for physical dimensions, you can find them here

Use Frequency, it looks nicer and is more explicit

julia> using Unitful; using Unitful: s, Hz, Frequency

julia> f(x::Frequency) = 2x
f (generic function with 1 method)

julia> f(2Hz)
4 Hz

julia> f(1/2s)
1.0 s^-1
3 Likes

Ok dispatch like that absolutely makes sense then! So yes, as Mason pointed out is the way. I couldn’t tell if you were a newb trying to do something weird with units you don’t actually need to do :wink:

Glad you’re finding DimensionalData.jl useful :slight_smile:

1 Like

Ah, yes. This is the most elegant solution, thanks, it is quite well hidden though :wink:.