Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upDesign By Contract #1077
Comments
This comment has been minimized.
This comment has been minimized.
gsingh93
commented
Apr 20, 2015
|
I don't know much about this, but is this related: https://github.com/nrc/libhoare Also, we're not post-1.0 yet :) |
This comment has been minimized.
This comment has been minimized.
|
The beta is not considered post-1.0? |
This comment has been minimized.
This comment has been minimized.
gsingh93
commented
Apr 20, 2015
|
Post 1.0 is after May 15th, when the real 1.0 is out. |
This comment has been minimized.
This comment has been minimized.
|
DBC looks like one of these things that should be a syntax extension. |
This comment has been minimized.
This comment has been minimized.
DiamondLovesYou
commented
Apr 20, 2015
|
@arielb1 I disagree. Syntax extensions have no access to type resolved results. I believe what one would actually want would be a compiler plugin. |
This comment has been minimized.
This comment has been minimized.
gsingh93
commented
Apr 20, 2015
|
@DiamondLovesYou I thought syntax extensions and compiler plugins were the same thing. Can you give an example of each? |
This comment has been minimized.
This comment has been minimized.
|
@gsingh93 I edited the tense in the original post. @DiamondLovesYou I would also like an example of each. |
This comment has been minimized.
This comment has been minimized.
|
@DiamondLovesYou what do you want type information for? As it stands at the moment, there are many things which are compiler plugins - these include procedural macros (aka syntax extensions), pluggable lints, and pluggable llvm passes. We also expose an API to the compiler to allow building custom compilers which have access to type info and everything else the compiler does. It seems to me that DBC can be (at least partially) implemented as a syntax extension (libhoare is a proof of concept of this). If there is lots of interest and use in a syntax extensions, then it might be worth experimenting with a custom compiler to support more DBC features which can't be implemented as a syntax extension. If that is successful, then I think we can discuss moving things into the compiler proper. As it stands I think any conversation about going straight to language features is not going to progress very far or quickly. We should also have more powerful syntax extensions available in the medium term future, they should allow better syntax for things like DBC without having to have core language support. |
This comment has been minimized.
This comment has been minimized.
|
Anyway, what is design by contract? Rust has a powerful type system that already handles the 90% most popular propositions. |
This comment has been minimized.
This comment has been minimized.
|
I mean, the Rust type-system covers at least:
And that's at least 80% of all propositions already. |
This comment has been minimized.
This comment has been minimized.
|
The purpose of Design By Contract is to make bugs almost non-exist at all times, thus very fast developing. The syntax for DBC is self-documenting, so you should almost never have a single comment in all your code, while at the same time, someone who has never taken even his or her first programming class can know exactly what your program does without any other documentation. Design By Contract is a design concept for contractors to require that the world around them is in a certain state and for the world to be ensured by the contractor that the world will be in a specific state when the contractor's job is done. A contractor is a routine/method/procedure/function. You can stop reading here, unless you want more info.
An Eiffel example from The Pragmatic Programmer, page 114 sqrt: DOUBLE is
-- Square root routine
require
sqrt_arg_must_be_positive: Current >= 0;
--- ...
--- calculate square root here
--- ...
ensure
((Result*Result) - Current).abs <= epsilon*Current.abs;
-- Result should be within error tolerance
end;Though, this can be improved to be truly readable by fusing comments and what they are commenting into well-named routines. This, as a result, would eliminate repeating words, meaning your eyes should be able to glaze over just once and not waste time searching for something. |
This comment has been minimized.
This comment has been minimized.
gsingh93
commented
Apr 20, 2015
|
@KingOfThePirates Can you look at |
This comment has been minimized.
This comment has been minimized.
|
I am sure it covers everything, except standards. I am not needing Rust to change anything at all.. for my personal projects. What I need, and of course everyone, is to have standards prepared for the future, when Rust is used by mainstream in businesses and such. Plus Rust, being so early in development, why not have this powerful tool implemented in the language (I'd simply do it myself if I didn't start programming just since December)? |
This comment has been minimized.
This comment has been minimized.
gsingh93
commented
Apr 21, 2015
Because if we rush into things early, we're stuck with them forever. If this is a feature people want to use, they'll use the library, and if the library has enough use from the community, at that point it can be integrated into the language. |
This comment has been minimized.
This comment has been minimized.
|
I agree, which is part of the reason why I posted this. I wanted to know how many were interested. To me, who began programming with Code Complete, it seems silly to not implement these tools since we invented them. But I understand there are many who are unaware of concepts such as this one. No matter what, there will be a language that is what I want, in the next decade or two, because if there isn't, I'll make it, but having it now would be awesome. The reason why I am even using Rust as my first language while it is in early development is simply because I like it and its community. It isn't that bad that many of its members don't like every design concept that I like or as much as I like them. I still like this place so I'll stay here for awhile. Since I'm new to programming, could you tell me why you think modern design concepts such as DBC are not simply in the standards of all coding? |
This comment has been minimized.
This comment has been minimized.
|
@KingOfThePirates Techniques such as DBC have their place, but they are by no means universal (or even modern: DBC has been around since 1986!). With all of these sort of techniques, they're only useful if they can catch the kind of mistakes that you make often - in practice, I've found that DBC simply catches the wrong types of error, and that I'd have spent my time better writing more tests or documentation. |
This comment has been minimized.
This comment has been minimized.
|
@Diggsey Oh, thank you :) |
This comment has been minimized.
This comment has been minimized.
|
@nrc Thank you for your time and consideration. Looks like we must listen to what nrc said on this matter.
Rust gods: Please make sure to consider libhoare's wish list when making these "medium term future" syntax extension changes:
Edit 1 (Wednesday, April 22, 2015):
A higher up should close this if they deem it should be. I am unsure on whether or not others who might have Rust Design By Contract questions will be able to find this easily if it is closed. P.S. This reddit post can branch off to some good information on DBC in Rust. |
This comment has been minimized.
This comment has been minimized.
Thiez
commented
Apr 21, 2015
|
It appears libhoare does not support loop invariants. Having those will be required (in almost all cases) to prove programs correct, so if we ever want to do static checking rather than runtime assertion checking those will be needed. |
This comment has been minimized.
This comment has been minimized.
gsingh93
commented
Apr 22, 2015
|
To add loop invariants, I'm assuming we'd want to annotate the loop with an attribute, and so syntax extensions would need to be extended to apply to constructs other than top level items |
This comment has been minimized.
This comment has been minimized.
gsingh93
commented
Apr 22, 2015
|
But honestly, static checking of things like this are better left to dependent type systems. I'd be fine just putting an assertion in my loop instead. |
This comment has been minimized.
This comment has been minimized.
Thiez
commented
Apr 22, 2015
|
I would assume that it is more likely that external tools will be written to perform static checking of Rust code than that the Rust type system will be extended in such a way that it is sufficiently powerful to perform full correctness proofs. Surely it would be awesome if we had the Rust-equivalent of tools such as KeY and OpenJML? Edit: of course JML shows that the annotations do not need to be "real" annotations but can be inside comments, and it may be better if Rust goes that way as well. In that case no language support is required. |
This comment has been minimized.
This comment has been minimized.
Zaerei
commented
Apr 30, 2015
|
I think I'd prefer proofs to DBC. Though one could argue that DBC is a special, simple case of proofs, I think it would be impossible to implement a static proof system without accidentally implementing a DBC system as well. Essentially, it would be nice to be able to have constructive proofs on types, evaluated at compile time. Note that these are constructive -- that is, not being able to create a proof makes no claims about its falsehood, but being able to make one does imply truth. Further, if an input doesn't meet certain guarantees, it should probably be a warning, because some things may not be statically provable (esp. due to the halting problem). For instance, maybe I define a function that determines if a tree with the trait
That is, for any tree implementing my trait, assuming that we have a proof that the function is_finite evaluates to true and a proof that t.contains(n) is true, running depth-first-search on my tree will return a path instead of None. (Assuming Certain proofs could also be suggested on inputs (#[suggest]), as opposed to required like in DBC. For instance, for some concrete implementations of MyTree, I may not be able to prove is_finite for various and somewhat obvious reasons, but I still want to use DFS on MyTree. This would be a warning something like "Suggested proof DFSComplete cannot be validated because the assumption is_finite is not proven for MyConcreteTree. Use #[allow(no_proof)] to disable". A stronger tag like #[require] could be used for DBC, where it's an outright error if a proof isn't provided, but I'd be worried about people trying to #[require] proofs too frequently on proofs that may not be provable for many valid inputs. This would be extremely difficult to implement, though, and I wouldn't expect to see it for a long time, if ever. Automated proof systems are very hard, especially when AFAIK Rust's type system doesn't even have partial formal proofs yet. If this did exist, it may allow some compiler re-factoring, though, shuffing off a lot of the lifetime detection to the proof system. |
This comment has been minimized.
This comment has been minimized.
gsingh93
commented
Apr 30, 2015
|
I don't think baking this into the type system is a very good idea, as Rust would end up being a very different language. It seems like you're suggesting a dependent type system, and I don't think that's a good fit for Rust. A better solution is probably to implement some front-end for existing tools that do formal verification, like krakatoa. The output can be sent to some other formal verification tool that can do the proving. |
This comment has been minimized.
This comment has been minimized.
rfielding
commented
Aug 13, 2015
|
I believe that APIs annotated with DBC enable the creation of extensively self-documenting code, and being able to specify - to the compiler - what compliant API usage means, no? If you have a collection of functions with pre/post conditions, you can generate state transition diagrams (where states are nodes specifying conditions, and edges are function calls that transition from precondition to postcondition nodes), and check/generate message sequence diagrams. It looks a lot like what you get out of LANGSEC where you have decidable protocols between modules (particularly at security sensitive points getting messages from sockets and disks.) Even if only used as a library, not having DBC seems to be the key culprit in having large code bases that diverge from the documentation once implementation gets underway; as it's a matter of contracts making quite robust interfaces. An important thing about contracts: You should not need to specify what the compiler can infer. And you should not to explicitly log or trace contract usage and contract violations. If a debug build logged contract-relevant messages and state changes, there would be little explicit logging being done at the boundaries between modules. I definitely agree that it gets close to having dependent types. But contract violations that are only detectable at run-time are a slightly different beast. In that case, it's more like having a transparent proxy around an allocated object to do something useful when the contract is violated (ie: panic or log the problem), which is different from error conditions that are part of the contract that must be observed by explicitly handling error conditions (ie: handling bad input as opposed to internal inconsistencies). |
This comment has been minimized.
This comment has been minimized.
nixpulvis
commented
Feb 24, 2016
|
It's too bad discussion has died down here, as this is a feature I'd kill to see in the language. Regardless of what compiler support it needs giving programmers a standard way of writing down contracts would be huge. There has been a pretty wide variety of comments here about types. I'm not sure that Rust's contracts would need to change anything about the type system. Contracts are by design runtime checks that generally fit outside the type system of the language your in. You can even think to write weird contracts like one that ensures a function is only called after 6PM and before 8PM. There are a few subtitles with contracts in terms of implementation, but I think it's worth doing because it would allow programmers to fully express the invariants of their program to the level they desire, either as types (when possible) or as contracts for runtime checks. Rust appeals to a number of different people, for those who use it for C like speed, maybe contracts are a feature you will not use, but for those worried about safety in the most general sense of the word, contracts let you express more checks in a standard way. Further contracts if implemented correctly are a huge help for debugging, as they can assign blame to the failing party. There have been a number of papers written on this, a good place to start might be http://www.ccs.neu.edu/racket/pubs/popl11-dfff.pdf. |
This comment has been minimized.
This comment has been minimized.
|
A thread doesn't die until all the subscribers do. This discussion will continue. I need to learn more to speak intelligently on the matter, though. I've been learning a new Industry for the past year. I'm finally at a point where I can get back to my passion at github :) But I think I started this conversation earlier than I was ready for. I don't know enough. But I will learn. |
This comment has been minimized.
This comment has been minimized.
|
@Jragonmiris Proofs look interesting. Might not solve the same problems Design By Contract solves, but it looks like it can be useful. |
This comment has been minimized.
This comment has been minimized.
burdges
commented
May 7, 2016
|
It's worth skimming the accepted RFC on impl specilization (closing, tracking). In that thread, idea that documentation practices of clearly stating invariance required of specializations could supersede parametricity proved influential. It appears the proposed documentation practices would benefit substantially from a design by contract tool. In particular, we need an ability to specify that a method in a specialized We envisioned humans checking these invariants, but perhaps one could reference the overloaded method to automate some checks. If this specification generates code, then it could only run in certain debugging situations, maybe quickcheck like tests, of course. |
nrc
added
the
T-lang
label
Aug 30, 2016
This comment has been minimized.
This comment has been minimized.
socumbersome
commented
Dec 14, 2016
|
Hello fellow Rustaceans! :) I'm also a CS student and thought that implementation of DBC could make a nice thesis topic. So, my impression is that both DBC and proof system should be feasible to do as separate plugins to
Now, I imagine most of us would prefer to state theorem about some function, prove it, and let Rust verify it at compile time if performance is critical. But I think it shouldn't refrain us from having DBC (i.e. runtime checks), because, quite reasonably, which one I use depends on what I want :) And I certainly would want DBC when I want to state that my
Does my proposition sound okay? |
This comment has been minimized.
This comment has been minimized.
Thiez
commented
Dec 14, 2016
|
A potential challenge is that Rust doesn't really have any notion of purity. Something like If I may suggest a problem of a perhaps more limited scope: proving that |
This comment has been minimized.
This comment has been minimized.
nixpulvis
commented
Dec 14, 2016
|
Might be best to focus on the runtime contract system, that alone is worth something since it's going to be more powerful than Rust's type system. Being able to check pre and post conditions with arbitrary rust code is the main feature I'd want. And maybe a nice syntax for creating and composing contracts. Dealing with contracts with higher order functions is going to be the hairy part of the implementation most likely. |
This comment has been minimized.
This comment has been minimized.
gsingh93
commented
Dec 15, 2016
|
@socumbersome what would you provide that isn't already in https://github.com/nrc/libhoare? |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Dec 15, 2016
|
It sounds like DBC is meant to operate below the type level? Even if so, an awful lot can be lifted to the type level with wrapper newtypes, so.. An idea might be built in debug assertion traits each with a single method that gets invoked at different places in debug builds:
Aside from debug builds, there might be work on the LLVM side to make massively duplicated assertions optimize well, fast, correctly, etc. As an aside, I think the units crate looks interesting for ensuring measurement unit-like invariants. There is probably more that could be done with more careful usage of wrapper types like that. |
This comment has been minimized.
This comment has been minimized.
socumbersome
commented
Dec 15, 2016
|
@Thiez - yes, being able to reason about purity looks important here. I wonder whether it would be best to first do #1631 and then DBC/PS, or just proceed with DBC/PS and, until Effect System is ready, check purity in some hacky way (if possible). Also, a possibly crazy idea occurred to me -- maybe it would make sense to have impure computations inside preconditions as long as the following hold:
Now, why on earth would I want IO in a "Out" sense (if I swapped the meaning by accident, I mean here reading from files etc.)? Well, for example, one could have a functions that performs some dangerous computations with chemicals or whatnot, and it's only safe to do that if some sensor has not too high temperature -- so, reading from a dynamically changing file! I don't know how far-fetched my example is, though :P @gsingh93 - if we talk about DBC without PS and agree on separation of those, then in |
This comment has been minimized.
This comment has been minimized.
nixpulvis
commented
Dec 15, 2016
•
|
There is some precedence for stateful contracts, for example you could read the paper on Stateful Contracts for Affine Types which implements a runtime check similar to Rust's own type system in some ways. Many of these limitations might be pragmatic, but not necessary for the design. |
This comment has been minimized.
This comment has been minimized.
JaneSmith
commented
Aug 31, 2017
|
I'd just like to chime in with my support for this. Coming from a C#/.NET background (where Code Contracts exist, and are awesome), I would absolutely love to have DBC in Rust. |
This comment has been minimized.
This comment has been minimized.
HunterGraubard
commented
Sep 4, 2017
|
I think this would be a great feature. One possible disadvantage I can think of with the libhoare library is... That would work for custom user code, but not for existing standard library code. With Microsoft's Code Contracts, for example, contracts have been written for a significant portion of the standard library. People can use the standard library without using contracts, but if they do care about and use contracts, they immediately get support on it from the standard library. |
This comment has been minimized.
This comment has been minimized.
ErichDonGubler
commented
Sep 25, 2017
•
|
After discovering this issue, I'd like to mention that I'm actually developing a D-inspired macro library called Adhesion that lets you use Here's an example from the project README: use std::i32;
contract! {
fn add_one_to_odd(x: i32) -> i32 {
post(y) {
assert!(y - 1 == x, "reverse operation did not produce input");
}
body {
x + 1
}
pre {
assert!(x != i32::MAX, "cannot add one to input at max of number range");
assert!(x % 2 != 0, "evens ain't appropriate here");
}
}
}
assert!(add_one_to_odd(3) == 4);
assert!(add_one_to_odd(5) == 6);
// use the galvanic-assert crate for expected panics
assert_that!(add_one_to_odd(2), panics);
assert_that!(add_one_to_odd(i32::MAX), panics); |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Jan 19, 2018
|
Anyone considered "trait integration tests" as a step towards DBC? Right now, you could add macros that generate test code to test trait
In this, the You might need the |
This comment has been minimized.
This comment has been minimized.
|
@burdges I haven't seen that idea before, and it jumps out to me as the only "DBC" idea so far that might actually deserve to be a core language feature (this thread has always puzzled me since all of the concrete suggestions seemed just fine as a crate). For now I suppose you can still get a meaningful proof of concept in a crate by simply requiring the client to put your magic test-generating macro in their test module. But the general idea that a library may want to "impose" (suggest?) tests on all of its client crates seems like something worth adding to https://internals.rust-lang.org/t/past-present-and-future-for-rust-testing/6354 |
burdges
referenced this issue
Feb 2, 2018
Open
RFC: Overconstraining and omitting `unsafe` in impls of `unsafe` trait methods #2316
This comment has been minimized.
This comment has been minimized.
zpgaal
commented
Feb 7, 2018
|
Just a small comment on macro/lib/ language based solution for contract based programming. First i think everyone should read http://joeduffyblog.com/2016/02/07/the-error-model/ it is a good blog about the issue. Many thing can be done using lib level solutions, but I'd prefer the language level contract
|
This comment has been minimized.
This comment has been minimized.
burdges
commented
Feb 26, 2018
|
Yes, I liked his explanation that contracts represent part of the type signature of a function, or presumably a type. I noticed he also recommended range types over contracts when possible, which likely means full refinement types in Rust's context. |
KingOfThePirates commentedApr 20, 2015
As of right now, this discussion is expected to be super abstract.
Rust is a beautiful language because it is modern and built with common sense. Though it still lacks features that no modern language should. This discussion is only for one of those features. We are almost post-1.0, and, around that time, we should be thinking about how DBC, one of the most useful tools a programmer could use, should be used in Rust.
The only thing we have to worry about right now is when to actually have this discussion. It should be soon, but soon might mean many months from now.
So, when do you think official Rust-supported DBC solutions should be discussed?