@@ -12,6 +12,7 @@ no runtime cost.
1212- **abstract.jl**: Root abstract type `AbstractTrait` and family abstractions
1313- **time_dependence.jl**: Time-dependence traits and the opt-in contract
1414- **variable_dependence.jl**: Variable-dependence traits and the opt-in contract
15+ - **control_dependence.jl**: Control-dependence traits and the opt-in contract
1516- **mutability.jl**: Mutability traits and the opt-in contract
1617- **mode.jl**: Integration-mode traits (`EndPointMode`, `TrajectoryMode`)
1718- **dynamics.jl**: Dynamics-type traits (`StateDynamics`, `HamiltonianDynamics`, `AugmentedHamiltonianDynamics`)
@@ -25,23 +26,39 @@ no runtime cost.
2526
2627- **Time dependence**: `TimeDependence`, `Autonomous`, `NonAutonomous`
2728- **Variable dependence**: `VariableDependence`, `Fixed`, `NonFixed`
29+ - **Control dependence**: `ControlDependence`, `ControlFree`, `WithControl`
2830- **Mutability**: `InPlace`, `OutOfPlace`
2931- **Integration mode**: `EndPointMode`, `TrajectoryMode`
3032- **Dynamics**: `StateDynamics`, `HamiltonianDynamics`, `AugmentedHamiltonianDynamics`
3133- **Automatic differentiation**: `WithAD`, `WithoutAD`
3234- **Variable costate**: `SupportsVariableCostate`, `NoVariableCostate`
3335
34- ## Trait contract
35-
36- For time-dependence, variable-dependence, and mutability, a type opts in by
37- implementing two methods — `has_<family>_trait` returning `true`, and an accessor
38- (`time_dependence`, `variable_dependence`, `mutability`) returning the trait type.
39- Boolean predicates (`is_autonomous`, `is_variable`, `is_inplace`, …) are then
40- derived generically.
41-
42- The remaining families (`EndPointMode`, `StateDynamics`, `WithAD`,
43- `SupportsVariableCostate`) are used as type parameters only and do not use the
44- two-method contract.
36+ ## Trait contracts — two templates
37+
38+ Trait families follow one of two contracts. The choice is dictated by a single
39+ question: **does a safe default value exist?**
40+
41+ **1. Strict opt-in (no safe default).** Time-dependence, variable-dependence,
42+ control-dependence, and mutability. Guessing a value silently would be a
43+ correctness bug (an object is *either* autonomous or not), so there is no default:
44+ a type must opt in by implementing two methods — `has_<family>_trait` returning
45+ `true`, and an accessor (`time_dependence`, `variable_dependence`,
46+ `control_dependence`, `mutability`) returning the trait type. The fallbacks throw
47+ loudly ([`CTBase.Exceptions.IncorrectArgument`](@ref) /
48+ [`CTBase.Exceptions.NotImplemented`](@ref)) via the shared helpers
49+ `_throw_missing_trait` / `_throw_trait_not_implemented`. Boolean predicates
50+ (`is_autonomous`, `is_variable`, `is_control_free`, `is_inplace`, …) are derived
51+ generically.
52+
53+ **2. Default-valued capability (safe default exists).** Automatic differentiation
54+ (`ad_trait(::Any) = WithoutAD`) and variable-costate
55+ (`variable_costate_trait(::Any) = NoVariableCostate`). These are *capabilities*: a
56+ conservative "no" is always safe, so the extractor returns a default for any object
57+ and concrete types override it. No `has_<family>_trait` guard, no derived predicates.
58+
59+ The remaining families (`EndPointMode`, `StateDynamics`) are used as type
60+ parameters only (read from a concrete type's parameters, e.g.
61+ `AbstractSystem{TD,VD,D}`) and use neither contract.
4562"""
4663module Traits
4764
@@ -65,6 +82,7 @@ include(joinpath(@__DIR__, "variable_costate.jl"))
6582include (joinpath (@__DIR__ , " mutability.jl" ))
6683include (joinpath (@__DIR__ , " time_dependence.jl" ))
6784include (joinpath (@__DIR__ , " variable_dependence.jl" ))
85+ include (joinpath (@__DIR__ , " control_dependence.jl" ))
6886
6987# ==============================================================================
7088# Module exports
@@ -82,10 +100,13 @@ export InPlace, OutOfPlace
82100export WithAD, WithoutAD
83101export SupportsVariableCostate, NoVariableCostate
84102export VariableDependence, Fixed, NonFixed
103+ export ControlDependence, ControlFree, WithControl
85104export ad_trait, variable_costate_trait, dynamics_trait
86105export is_inplace, is_outofplace
87106export is_autonomous, is_nonautonomous, is_variable, is_nonvariable, has_variable
107+ export is_control_free, has_control
88108export has_time_dependence_trait, time_dependence, has_mutability_trait, mutability
89109export has_variable_dependence_trait, variable_dependence
110+ export has_control_dependence_trait, control_dependence
90111
91112end # module Traits
0 commit comments