I’ve seen topics touching this in different constellations, but:
How do people create a new type that would magically behave just like any subtype of (say) Number? So for example, if:
struct A{T <: Number}
x::T
end
then I’d just be able to *, +, sin, exp, or sqrt instances of A and on top of that I’d still be able to (re)define additional specialized methods like say sqrt(a::A) = (a.x)^(1/3)?
No no, I understand. But I had hoped that if I wanted to mimic, say, Float64, then there would have been an easy way to do that. Kind of like, in stead of starting from scratch: “here is a new type, you don’t know anything about it, let me tell you all you need to know about it”, starting from the top and “adjusting down”: “here is a new type, it’s exactly like Float64, except in this and this and that case”…
module PseudoNumbers
export PseudoNumber, getnumber # this is the interface
abstract type PseudoNumber end
function getnumber end
import Base: + # and the rest ...
# should define for univariate and multivariate operators using macros,
# this is just an example
+(a::T, b::T) where {T <: PseudoNumber} = T(getnumber(a) + getnumber(b))
end
and then all the code you would need to write is
using PseudoNumbers
struct MyFloat{T} <: PseudoNumber
x::T
end
PseudoNumbers.getnumber(mf::MyFloat) = mf.x
MyFloat(1.0) + MyFloat(2.0) # works out of the box
but I expect you would have to think about corner cases (lifting reals, how to combine two different types, etc).
While you can implement all the methods that a normal number has for your custom type, there is one thing where it gets tricky: do you want to inherit from Number or not? If you don’t, you can’t pass instances of your type to functions that only accept Numbers, even if your type behaves like a number. I don’t think there is a good solution to this right now, we’ll probably have to wait for either traits or interfaces in some future julia version for an elegant solution.
A few weeks ago @Per shared the intention to work on a library that may suit your needs, if your type will be a subtype of AbstractFloat (but it may not be the case):
Sounds great. I’m working on the tests now, but this whole thing is just for my idea with the Angle type. I defined all the functions needed for the conversions and the trigonometry, but now “all” I need is for this Angle type to behave like a Number (or AbstractFloat) in every other situation…
The real problem is that promotion rules are defined for mixed operations on different types, e.g. if you do a + b where a and b are different Number types then it will call promote(a,b) by default. This doesn’t help you at all for exp(x), for example, or for non-Number types, where the promotion code is not called in the default methods.