Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unitful.Angle? #216

Open
m-wells opened this issue Mar 27, 2019 · 11 comments
Open

Unitful.Angle? #216

m-wells opened this issue Mar 27, 2019 · 11 comments

Comments

@m-wells
Copy link

m-wells commented Mar 27, 2019

Perhaps a callback to #38 I think it would be useful to define an Angle "type".

I've hacked this
const Angle = Union{typeof(1rad),typeof(1.0rad),typeof(1°),typeof(1.0°)}
I don't see how this would be inherently different from something like Unitful.Time.

This is most useful in terms of dispatch. Structures benefit from concrete types.

@giordano
Copy link
Collaborator

It's already a thing https://github.com/yakir12/UnitfulAngles.jl 😉

@m-wells
Copy link
Author

m-wells commented Mar 27, 2019

@giordano Thanks for the reply but I don't see a type declaration that would allow me to do something like
f(x::UnitfulAngles.Angle) = sin(x) where x could be x=2u"°" or x=2u"rad"

@giordano
Copy link
Collaborator

Ah, if you really want a type then no, there is no new type nor alias, there.

I've hacked this
const Angle = Union{typeof(1rad),typeof(1.0rad),typeof(1°),typeof(1.0°)}
I don't see how this would be inherently different from something like Unitful.Time.

Unless you really want to restrict to Ints, I'd suggest you to define the constant as

const Angle{T} = Quantity{T, NoDims, u"rad"}

which is independent from the type of the value

@m-wells
Copy link
Author

m-wells commented Mar 27, 2019

@giordano The method you suggest yields the following

julia> using Unitful

julia> const Angle{T} = Quantity{T,NoDims,u"rad"}
Quantity{T,NoDims,rad} where T

julia> f(x::Angle) = sin(x)
f (generic function with 1 method)

julia> f(1.2u"°")
ERROR: MethodError: no method matching f(::Quantity{Float64,NoDims,Unitful.FreeUnits{(°,),NoDims,nothing}})
Closest candidates are:
  f(::Quantity{T,NoDims,rad} where T) at REPL[3]:1
Stacktrace:
 [1] top-level scope at none:0

julia> f(1.2u"rad")
ERROR: MethodError: no method matching f(::Quantity{Float64,NoDims,Unitful.FreeUnits{(rad,),NoDims,nothing}})
Closest candidates are:
  f(::Quantity{T,NoDims,rad} where T) at REPL[3]:1
Stacktrace:
 [1] top-level scope at none:0

while my hack yields what I find to be the desired behavior

julia> import Unitful: °, rad

julia> const Angle = Union{typeof(1rad),typeof(1.0rad),typeof(1°),typeof(1.0°)}
Union{Quantity{Float64,NoDims,FreeUnits{(rad,),NoDims,nothing}}, Quantity{Float64,NoDims,FreeUnits{(°,),NoDims,nothing}}, Quantity{Int64,NoDims,FreeUnits{(rad,),NoDims,nothing}}, Quantity{Int64,NoDims,FreeUnits{(°,),NoDims,nothing}}}

julia> f(x::Angle) = sin(x)
f (generic function with 1 method)

julia> f(30°)
0.5

julia> f*rad/6)
0.49999999999999994

julia> f(30)
ERROR: MethodError: no method matching f(::Int64)
Closest candidates are:
  f(::Union{Quantity{Float64,NoDims,FreeUnits{(rad,),NoDims,nothing}}, Quantity{Float64,NoDims,FreeUnits{(°,),NoDims,nothing}}, Quantity{Int64,NoDims,FreeUnits{(rad,),NoDims,nothing}}, Quantity{Int64,NoDims,FreeUnits{(°,),NoDims,nothing}}}) at REPL[3]:1
Stacktrace:
 [1] top-level scope at none:0

It also isn't restricted to Int

julia> f(30.1°)
0.5015107371594574

@giordano
Copy link
Collaborator

giordano commented Mar 27, 2019

@giordano The method you suggest yields the following

That's because I misspelled the last argument to Quantity, it should have been

julia> const Angle{T} = Quantity{T, NoDims, typeof(u"rad")}
Quantity{T,NoDims,Unitful.FreeUnits{(rad,),NoDims,nothing}} where T

julia> f(x::Angle{T}) where {T<:Number} = sin(x)
f (generic function with 1 method)

julia> f(pi*u"rad")
1.2246467991473532e-16

julia> f(1u"rad")
0.8414709848078965

julia> f(3.14u"rad")
0.0015926529164868282

Your solution works only with the type you pass to the Union, not with any Number type, including custom ones. For example, with Irrational (which is not even custom but a standard one) you get:

julia> f(pi*u"rad")
ERROR: MethodError: no method matching f(::Quantity{Irrational{:π},NoDims,Unitful.FreeUnits{(rad,),NoDims,nothing}})
Closest candidates are:
  f(::Union{Quantity{Float64,NoDims,FreeUnits{(rad,),NoDims,nothing}}, Quantity{Float64,NoDims,FreeUnits{(°,),NoDims,nothing}}, Quantity{Int64,NoDims,FreeUnits{(rad,),NoDims,nothing}}, Quantity{Int64,NoDims,FreeUnits{(°,),NoDims,nothing}}}) at REPL[6]:1
  f(::Quantity{T,NoDims,rad}) where T at REPL[10]:1
Stacktrace:
 [1] top-level scope at none:0

@m-wells
Copy link
Author

m-wells commented Mar 27, 2019

I like your type definition of

julia> const Angle{T} = Quantity{T, NoDims, typeof(u"rad")}
Quantity{T,NoDims,Unitful.FreeUnits{(rad,),NoDims,nothing}} where T

Would this be something worth considering for inclusion in Unitful?

@m-wells
Copy link
Author

m-wells commented Apr 9, 2019

I've opened a (fairly ambitious) pull request #221. I would appreciate feedback.

@ajkeller34
Copy link
Collaborator

I don't think there is a perfect solution for dispatching on a Unitful.Angle type, because a) angles are dimensionless (see #38 (comment)) and b) one could always define new angle units, which means any union of types you define to try and cover all angle types won't be generic. My impression is that most people use either radians or degrees, in which case you could define the following, or make an even larger union with other units:

Angle{T} = Union{Quantity{T,NoDims,typeof(u"rad")}, Quantity{T,NoDims,typeof(u"°")}} where T

@m-wells this is of course a simple extension of what @giordano wrote but I wanted to be sure you realized you had this option.

@bhalonen
Copy link

bhalonen commented Jul 10, 2019

Angles may be dimensionless, but they certainly aren't context-less. There are very specific things you can do with an angle

@cmichelenstrofer
Copy link
Contributor

I just created a DimensionfulAngles.jl package. It treats angles as a dimension which allows for dispatching. Check it out!

@jariji
Copy link

jariji commented Apr 5, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants