I am working with the DifferentialEquations package to play around some differential equations involving angles.
Instead of letting everything go on as a normal float and just afterwards reduce everything modulo 2pi for visualisation, i wanted to try to go the julian way and define a small wrapper for the Floag64 type
struct Angle <: Real
Angle(x::Real) = Angle(x % 2pi)
Unfortunately this is not enough to make for a smooth addition to my program as julia struggles to convert and does not know what to do with this new type.
I know that i can extend all the base operations by hand, but i was left wondering if there is a smoother and easier way to let a simple primitive Number type wrapper just automatically fall in place the rest of the Julia implementation.
More in general i tried to look for some quick guidelines when creating a new custom type but i could not find one. Are there any Best Practices ™ when it comes to seamlessly embed a new custom type in the language?
You should find an inspiration in manual describing the implementation of rational number.
Also, I think you can benefit from the macro
@forward that I describe in this reply of mine.
This is extremely interesting but the
@forward macro seems to not retain the type as in
struct Angle <: Real
@forward Angle.x Base.sqrt
typeof(Base.sqrt(Angle(1))) == Float64 #true
and that is not really what i need. Moreover, using forward on
Base.:+ raises a
MethodError anyway as there is ambiguity as the macro defines
+(x::Angle, args...; kwargs...)
I think i’ll stick the the “not lazy” version of embedding a custom type for now.
eval would be more the case here.
for single_param_function in (:(Base.sqrt), :(Base.sin))
function $(single_param_function)(a :: Angle)
Someone with better knowledge of metaprogramming should check if this is reasonable (it works, but maybe is not ideal).
Note that you will get more accurate results by using
mod2pi(x) instead of
x % 2pi (since the latter uses
Float64 approximation of the actual number 2π).
Is the sine of an angle another angle or just a number? If you don’t need it to be an angle, then simply defining
Base.float for your type will work for a lot of functions that use this as their fallback.
julia> Base.float(a::Angle) = a.x