# How should constant literals be typed in Differentiable Code?

**URL:** <https://discourse.julialang.org/t/how-should-constant-literals-be-typed-in-differentiable-code/131965>\
**Category:** Specific Domains\
**Tags:** differentiation\
**Created:** [August 30, 2025, 2:32pm UTC](https://discourse.julialang.org/t/how-should-constant-literals-be-typed-in-differentiable-code/131965 "2025-08-30T14:32:49Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![stevenhughes](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@stevenhughes](https://discourse.julialang.org/u/stevenhughes)\
**Post date:** [August 30, 2025, 2:32pm UTC](https://discourse.julialang.org/t/how-should-constant-literals-be-typed-in-differentiable-code/131965/1 "2025-08-30T14:32:49Z")

</div>

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 `NaN`s 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
