How should constant literals be typed in Differentiable Code?

Hello,
I wrote code that I now need to make differentiable. I’ve read the best practice docs, and my code is differentiating (REPL compile times are seriously painful though). I use AI to read my code to help me improve quality, catch errors, fix style issues. GPT 5 recommends treating “1.0” and “0.0” like this (my code is below to give context of state and the whole function).

T = eltype(state)
oneT = one(T)
zeroT = zero(T)

I understand why this is necessary if I am using arrays that may end up having elements that are not constant and need to be differentiable. But, is this really necessary for constants? It reduces code readability, for something that is obviously not differentiable anyway. I want to avoid this if possible, but don’t want to create subtle type issues if this nasty type side-effect is truly a thing.

Thanks for any help here.

BTW, general comments on the code are appreciated as I am about to finalize a style guide for functions in my library and this is a good example of where I am going.

using LinearAlgebra

“”"
kep_to_cart(state::Vector, μ; tol=1e-12)

Convert a Keplerian state vector to a Cartesian state vector.

Arguments

  • state::Vector: Keplerian elements [a, e, i, Ω, ω, ν]
  • μ: Gravitational parameter
  • tol: Tolerance for singularities like p ≈ 0 (default: 1e-12)
  • a: semi-major axis
  • e: eccentricity
  • i: inclination
  • Ω: right ascension of ascending node
  • ω: argument of periapsis
  • ν: true anomaly

Returns

A 6-element vector [x, y, z, vx, vy, vz] representing Cartesian position and velocity.

Notes

  • Angles must be in radians.
  • Dimensional quantities must be consistent units with μ.
  • Returns a vector of NaNs if conversion is undefined (e.g., p ≈ 0).
    “”"

function kep_to_cart(state::Vector, μ; tol=1e-12)
if length(state) != 6
error(“Input vector must have exactly six elements: a, e, i, Ω, ω, ν.”)
end

if μ < tol
    @warn "Conversion Failed: μ < tolerance."
    return fill(NaN, 6)
end

# Unpack the elements
a, e, i, Ω, ω, ν = state

# Compute semi-latus rectum: p = a * (1 - e²)
p = a * (1.0 - e^2)

# Check for degenerate orbit (e.g., parabolic or collapsed)
if p < tol || abs(1-e) < tol
    @warn "Conversion Failed: Orbit is parabolic or singular."
    return fill(NaN, 6)
end

# Compute radial distance: r = p / (1 + e * cos(ν))
r = p / (1.0 + e * cos(ν))

# Position and velocity in perifocal frame 
factor = sqrt(μ / p)
r̄ₚ = [r * cos(ν), r * sin(ν), 0.0]
v̄ₚ = [-factor * sin(ν), factor * (e + cos(ν)), 0.0]

# Precompute sines and cosines for rotation matrix
cos_Ω, sin_Ω = cos(Ω), sin(Ω)
cos_ω, sin_ω = cos(ω), sin(ω)
cos_i, sin_i = cos(i), sin(i)

# Rotation matrix from perifocal to inertial
R = [
    cos_ω * cos_Ω - sin_ω * cos_i * sin_Ω   -sin_ω * cos_Ω - cos_ω * cos_i * sin_Ω   sin_i * sin_Ω;
    cos_ω * sin_Ω + sin_ω * cos_i * cos_Ω   -sin_ω * sin_Ω + cos_ω * cos_i * cos_Ω  -sin_i * cos_Ω;
    sin_ω * sin_i                                    cos_ω * sin_i                   cos_i
]

# Rotate position and velocity to inertial frame
pos = R * r̄ₚ
vel = R * v̄ₚ 

return vcat(pos, vel)

end