# Evaluatable bounds: are they needed? If we do not require a proof that generic constants are evaluatable we end up with errors during monomorphization, which is badâ„¢ as these don't get detected by `cargo check`. ## Evaluatable bounds vs conditions TODO: Elaborate on the difference between `evaluatable { N - 1 }` and `is_true { N > 0 }`. It is not possible to rely on conditions to prevent errors during monomorphization by themselves, as it not possible for the compiler to prove that a condition completely covers the cases where some other constant panics. This is related to [silent CTFE errors](https://github.com/rust-lang/project-const-generics/issues/25). Having a lint which suggests adding conditions for each potentially panicking constant is also very difficult, as the compiler does not look into functions for this. We also again have the issue that having the compiler figure out with which inputs something causes a panic is impossible. ## Defining `evaluatable` A term is `evaluatable` if it does not panic or never exit. For example, `<const N:usize> ... evaluatable { N }` is satisfied, since N is known to be a `usize`, and is unmodified. As compared to that `evaluatable { loop {} }` is not satisfied, since it is of type `!`. There can be cases where it is not immediately clear that a function is not evaluatable. For example, `evaluatable { N - 1 }` may be unevaluatable since `0-1` will overflow and panic. Thus, we enforce that the given expression is well-defined and will not panic. As long as the expression does not evaluate to the `!` type, it will compile ## Defining `is_true` The condition `is_true` is more explicit than evaluatable. It enforces that a certain condition evaluates to a boolean, such as `is_true { N > 0 }`. The issue with this definition is that `is_true` may also evaluate to `!`, and it's not clear how to handle that case. For example, consider `is_true { N - 1 > 0 }`. What should the behavior be when `N=0`, since the expression will panic? From this, an intuitive definition is that `is_true` is actually a superset of `evaluatable`. Specifically, `is_true` is `evaluatable { <expr> } && <expr> == true`. It is possible to force `<expr>` to never panic, for example by switching `is_true { N -1 > 0 } => is_true { N > 1 }`. In some cases though, it may not be clear how to do this conversions. ## Comparing usability of `evaluatable` vs `is_true` TODO I think that `evaluatable` to an end-user is kind of opaque? `is_true` is very clear that an expression must evaluate to true, and doesnt' just panic, but maybe that is just me bike-shedding on `evaluatable` being hard to understand. I also wonder whether certain expressions are representable in `is_true` more easily, such as `N == 3, ID > 299 && ID < 500` and other things. ## Deferring Const Errors: In Haskell, certain type-level errors can be [deferred until run-time](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/defer_type_errors.html). It may be useful to provide such functionality. This would likely imply replacing expressions that are do not satisfy `evaluatable` with a panic. This seems bad in some cases, since a programmer may accidentally hit a sharp edge in their code where it is not clear that their const expression would cause a panic. Alternatively, it may make the common case much more ergonomic. If we were to include this, it might be possible to use warnings, or downgradable errors.