Even Rust's types aren't going to help you if two arguments simply have the same types.
Even Rust's types aren't going to help you if two arguments simply have the same types.
Or another (dummy) example transfer(accountA, accountB). Make two types that wrap the same type but one being a TargetAccount and the other SourceAccount.
Use the type system to help you, don’t fight it.
Sound type systems are equivalent to proof systems.
You can use them to design data structures where their mere eventual existence guarantee the coherence and validity of your program’s state.
The basic example is “Fin n” that carries at compile time the proof that you made the necessary bounds checks at runtime or by construction that you never exceeded some bound.
Some languages allow you to build entire type level state machines! (eg. to represent these transactions and transitions)