3 ms·
You have conveniently skipped the "Philosophical Objections" section in Wikipedia which i had pointed out and which would have given you some hints as to what i
by rramadass 1y ago
You have conveniently skipped the "Philosophical Objections" section in Wikipedia which i had pointed out and which would have given you some hints as to what i am saying.
> A proof of a program's correctness is mathematical in nature, it doesn't stand apart in some distinct non-mathematical realm ... I think this is really a disagreement on phraseology though, nothing deeper.
It is mathematical in nature but if the objects it deals with do not obey the axioms and/or the axioms are inconsistent the whole edifice falls. You can provide a perfectly "valid" proof but starting with wrong/inconsistent axioms. In computing since everything is a series of calculations it becomes quite important to make sure that you can carry-over the axioms in an algebra "as is" from pure mathematics to programming. In the example that i gave, the C language gives you multiple sets (aka types) of integers (i.e. cartesian product of {signed, unsigned} X {8, 16, 32, 64}) which are all subsets of the mathematical structure Z. You can distribute these types across the variables a/b/c in the expression in many different orders each of which have to be proven separately for the axiom of associativity to hold generally.
> Programming languages can be modelled mathematically. Programs can be modelled mathematically. That's much of the point of formal methods. Real computers are finite state machines. So what?
Mathematics is static/declarative while Computing has both static/structural and dynamic/behavioural aspects both of which are amenable to mathematics but differently. This is the fundamental difference. It is also the reason so much of real world software is pretty good and correct in spite of not using any formal methods whatsoever. A "Proof" is simply a logical argument from {Premises} -> {Conclusion} whether done informally or formally. When we write a program we are the proof deriver logically moving from statement to statement to produce the desired result. This is "proof by construction" where we show that the final product (i.e. the program) meets the desired properties. By using Defensive Programming and Testing techniques we then "prove" at runtime that the properties hold. DbC is a more formal method of doing the same. TDD can also be considered as belonging to the same category.
> As I understand it, in typical design-by-contract software development, there is no formal proving of anything, there's just runtime checking ... We only know that's the case if we've formally proven that the program is correct. If you're doing runtime checking, it's presumably because you don't know whether the program always does as you hope in all possible states.
This is your fundamental misunderstanding. By "Formal" you are only looking at static verification of the program and ignoring all runtime aspects. DbC is formal verification at runtime of a proof you have hand derived statically using set theory/predicate logic as you write the program. It does not make it any less than other formal methods done statically (hence the easy mapping done to VDbC). It is the real world needs of the system which decides what is acceptable as pointed out previously.
There is also a movement towards "lightweight formal methods" where partial specification, partial analysis, partial modeling and partial proofs are deemed acceptable because of the value they provide.
> It's not mere detail, it's an entirely different software engineering outcome. ... More generally, testing and runtime checking are able to discover bugs, but are typically incapable of proving the absence of bugs. This is much of the motivation for formal methods in the first place.
No amount of Formal Methods application can help you against something going wrong in the environment (hence my use of the word cataclysm) and which directly affects the system eg. a EMP pulse corrupting memory, hardware failures etc. We mitigate against this using Redundancy and Fault-Tolerance techniques. Because in computing we have static and dynamic aspects we need to consider both as the field of use for Formal (and other) Methods.
> Again I don't think it's helpful to phrase it as if there are 2 worlds here, one mathematical and one not.
There absolutely is. It is the definition of Ideal vs. Real Worlds. In Computing you have the limitations of finite time, finite steps, finite precision, finite error/accuracy etc. It changes the very nature of how you would map mathematics to reality.
References:
1) Proof by Construction - https://en.wikipedia.org/wiki/Mathematical_proof#Proof_by_construction https://en.wikipedia.org/wiki/Mathematical_proof#Proof_by_co...
2) Stackexchange and HN discussion Why is writing mathematical proofs more fault-proof than writing code? - https://news.ycombinator.com/item?id=16045581 https://news.ycombinator.com/item?id=16045581
3) When is a computer proof a proof? - https://lawrencecpaulson.github.io/2023/08/09/computer_proof.html https://lawrencecpaulson.github.io/2023/08/09/computer_proof...
4) The Central Dogma of Mathematical Formalism - https://siliconreckoner.substack.com/p/the-central-dogma-of-mathematical https://siliconreckoner.substack.com/p/the-central-dogma-of-...
5) Lightweight Formal Methods - https://people.csail.mit.edu/dnj/publications/ieee96-roundtable.html https://people.csail.mit.edu/dnj/publications/ieee96-roundta...
- MaxBarraclough 1y ago> You have conveniently skipped the "Philosophical Objections" section in Wikipedia As far as I can see, that Wikipedia section doesn't connect to anything we've discussed. We haven't discussed the impracticality of human verification of machine-generated proofs of properties of complex programs or models. We haven't discussed the possibility of bugs in verifier software. > It is mathematical in nature but if the objects it deals with do not obey the axioms and/or the axioms are inconsistent the whole edifice falls. Sure, but you seem to be stressing the risk of misapplication of mathematical axioms such as those of integer arithmetic, to contexts where they do not hold, such as arithmetic over int in the C language. As I've stated, formal methods are able to accommodate that kind of thing. We're both already aware of this. You can formally reason about a program written in C, but naturally you need to be keenly aware of the way C code behaves, i.e. the way the C language is defined. You need to model C's behaviour mathematically. As you've hinted at, you need to account for the way unsigned integer arithmetic overflow is defined as wrapping, whereas signed integer arithmetic overflow causes undefined behaviour. The formal model of the source programming language essentially forms a set of axioms. Existing tools already do this. > When we write a program we are the proof deriver logically moving from statement to statement to produce the desired result. This is "proof by construction" where we show that the final product (i.e. the program) meets the desired properties. I'm not clear what software development methodology you have in mind here. It sounds like you're describing a formal methodology. It certainly doesn't describe ordinary day-to-day programming. > By using Defensive Programming and Testing techniques we then "prove" at runtime that the properties hold. These do not constitute a proof over the program. > By using Defensive Programming and Testing techniques we then "prove" at runtime that the properties hold. DbC is a more formal method of doing the same. No, again, that isn't proof in the sense of serious formal reasoning about a program. I guess it's a proof in the trivial sense, courtesy of the Curry–Howard correspondence, but I don't think that's what you're referring to. In my prior comment I gave a list of reasons why runtime checking doesn't even necessarily prove that the program correctly implements a correspondence from the one particular input state to the one particular output state, as there's plenty of opportunity for the program to accidentally contain some form of nondeterminism such that it only happened to derive the correct output state when it actually ran. Program behaviour might be correct by coincidence, rather than correct by construction. Consider this C fragment by way of a concrete example. I'll use undefined behaviour as the root cause of troublesome nondeterminism, but as I mentioned in my earlier comment, another would be race-conditions. int i = 1 / 0; int k = 42; i = k; At the end of this sequence, what state is our program in, reasoning by following the definition of the C programming language as carefully as possible and making no assumptions about the specific target platform? Incorrect answer: i and k both hold 42, and execution can now continue. Variable i was briefly assigned a nonsense value by performing division by zero, but the last assignment renders this inconsequential. Correct answer: undefined behaviour has been invoked in the first statement. This being the case, the program's behaviour is not constrained by the C standard, so roughly speaking, anything can happen. On some platforms it may be that i and k both hold 42, and that execution can now continue without issue, but neither is guaranteed by the C language. Nothing that occurs subsequently in the program's execution can reverse the fact that undefined behaviour has been invoked. This is of course a trivial contrived example that's impossible to miss, but in practice, plenty of C programs accidentally rely on implementation-defined behaviour, and many accidentally invoke undefined behaviour, according to the C standard. Putting lots of assertions into your code isn't an effective way of catching that kind of issue in practice. If it were, we wouldn't have so many security issues arising from memory-management bugs. Even if all that weren't the case though, runtime testing still can't exhaustively cover all cases, whereas formal proofs can. > TDD can also be considered as belonging to the same category. No, that's really quite absurd. Try arguing to a formal methods research group that TDD is tantamount to formal verification. They'll laugh you out of the room. > DbC is formal verification at runtime of a proof you have hand derived statically using set theory/predicate logic as you write the program. For the reasons I gave above, it does not even definitively demonstrate the correctness of the code for a given input state, let alone in general. Most people doing 'design by contract' are not starting out with a formal model expressed in set theory. I think you should find another term to refer to the methodology you have in mind here, it's confusing to refer to this as 'design by contract'. You generally can't practically hand-derive proofs of properties of a large program or formal model, that's why computerised solutions are used. > There is also a movement towards "lightweight formal methods" where partial specification, partial analysis, partial modeling and partial proofs are deemed acceptable because of the value they provide. Sure, like I said earlier: I'm not opposed to the use of partial proofs or 'good enough' proof-sketches, both of which could be useful in producing high-quality software in the real world, but we should be clear in how we refer to them. Something I should have added at the time: when using a formal software development methodology, it's possible, and likely necessary for practical reasons, to prove only a subset of the properties that constitute the program's correctness. > No amount of Formal Methods application can help you against something going wrong in the environment Of course. > In Computing you have the limitations of finite time, finite steps, finite precision, finite error/accuracy etc. Right, but do any of these defy mathematical modelling? Limitations of that sort might make programs mathematically uninteresting, but that's almost the opposite of them being fundamentally irreducible to mathematics.