There are two cruical properties you want, I think:<p>A) It <i>must</i> be possible to automatically and completely mechanically ensure that implementation &amp; proof don&#x27;t get out of sync. Having a formal proof for an algorithm which isn&#x27;t the algorithm that you&#x27;ve actually ended up implementing doesn&#x27;t really help you one whit :). This is relatively simple for unit tests and property-based tests like QuickCheck: Just observe that the number of tests run actually increases over time and never decreases unexpectedly. (Actually, it seems to be rather rare to have support from Continuous Integration tools for tracking the latter.)<p>B) There must be (in some sense) at least some non-trivial difference between the implementation &amp; &quot;proof&quot;. (At the absurd extreme: bisimulation doesn&#x27;t really work as proof of anything if the implementations are one and the same.) For example, in Idris the implementation is basically just code while the proof is the accomanying types -- which ensures that they&#x27;re not basically just saying the (trivially) same thing, even though the types greatly <i>constrain</i> what the implementation can do.<p>I think that the allure of &quot;practical&quot; dependent types (e.g. Idris) may be that such languages trivially obey both properties. Of course you still end up with a &quot;trusted computing base&quot; which is non-trivial in such cases.