# Promotion rules for custom structs

I have a custom struct `Body` (shown below). For another struct, I’d like to be able to keep vectors of `Body` variables, and I’d like to be able to promote `Body{Float32}` to `Body{Float64}`, `Body{Float64}` to `Body{BigFloat}`, etc.

The following definition does run, but it still doesn’t allow for `Body` promotion.

``````julia> promote_rule(::Type{Body{A}}, ::Type{Body{B}}) where {A<:AbstractFloat, B<:AbstractFloat} = Body{promote_type(A, B)}

julia> b1 = Body(Float32.([1, 2, 3]u"m"), Float32.([1,2,3]u"m/s"), Float32(1u"kg"))

julia> b2 = Body(Float64.([1, 2, 3]u"m"), Float64.([1,2,3]u"m/s"), Float64(1u"kg"))

julia> promote(b1, b2)
ERROR: promotion of types Body{Float32} and Body{Float64} failed to change any arguments
``````

Is what I’m trying to do possible?

`Body` Definition:

``````using Unitful
using StaticArrays

struct Body{F<:AbstractFloat}

r̅::SVector{3, Unitful.Length{F}}
v̅::SVector{3, Unitful.Velocity{F}}
m::Unitful.Mass{F}

function Body(r::R, v::V, m::M) where {
T <: AbstractFloat,
R <: AbstractVector{Unitful.Length{T}},
V <: AbstractVector{Unitful.Velocity{T}},
M <: Unitful.Mass{T}
}

if length(r) ≢ length(v) ≢ 3
error("The `Body` constructor requires 3 element vectors for position `r` and velocity `v`")
else
return new{T}(SVector{3}(T.(r)), SVector{3}(T.(v)), M(T(m)))
end

end

end
``````

You need to make sure, you actually overload `Base.promote_rule`. What you are doing is defining a new function locally, that just happens to be called `promote_rule`.

5 Likes