question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal: Method Contracts

See original GitHub issue

(Note: this proposal was briefly discussed in #98, the C# design notes for Jan 21, 2015. It has not been updated based on the discussion that’s already occurred on that thread.)

Background

“Code Contracts” were introduced in .NET 4 as a feature of the Framework, primarily exposed through the System.Diagnostics.Contracts.Contract class. Through method calls like Contract.Requires and Contract.Ensures, developers could add code to their methods to specify preconditions and postconditions, and then a subsequent tool known as a rewriter could be used to post-process the code generated by the compiler to appropriately implement the expressed contracts, e.g. whereas the developer puts a call to Ensures at the beginning of the method, the rewriter ensures that path through the method that could cause it to exit ends with a validation of the expressed postcondition.

public int Insert(T item, int index)
{
    Contract.Requires(index >= 0 && index <= Count);
    Contract.Ensures(Contract.Result<int>() >= 0 && Contract.Result<int>() < Count);
    return InsertCore(item, index);
}

Problem

Very little code actually uses these API-based code contracts. They require additional tooling to be integrated into the build, they’re verbose, and it’s difficult to write additional robust tooling related to them (e.g. integrating contract information into documentation).

Solution: Language support for method contracts

Basic contract support for preconditions and postconditions can be built directly into the language, without requiring any separate tooling or custom build processes, and more thoroughly integrated throughout the language.

The compiler would generate all of the relevant code to correctly validate the contracts, and the contracts would show up as part of the method signature in the Visual Studio IDE, such as in IntelliSense at call sites to the method.

public int Insert(T item, int index)
    requires index >= 0 && index <= Count
    ensures return >= 0 && return < Count
{
    return InsertCore(item, index);
}

These contracts would primarily be validated at run time, however if the compiler (or a 3rd-party diagnostic) could statically detect a violated contract (e.g. a precondition requires that an argument be non-null, and null is being passed as the argument), it could choose to fail the compilation rather than allowing the bug to make its way to run time. Similarly, if the compiler (frontend or backend) is able to statically determine that a contract will always be satisfied, it can optimize based on that knowledge.

Unlike .NET Code Contracts, which have configurable but complicated behavior provided by a post-compilation rewriter tool (and which are no-ops if such a rewriter isn’t used), failed validation of ‘requires’ and ‘ensures’ clauses would ideally result in “fail fast” (ala Environment.FailFast(…)), meaning the program abandons immediately. This is very useful for validating preconditions and postconditions, which are typically used to catch usage errors by the developer. Such errors should never make it into production.

The compiler would require that preconditions and postconditions can be validated by the caller, and as such it requires that any members used in the requires and ensures clauses are all accessible to any caller, e.g. the requires clause of a public method may not access internal or private members, and the requires clause of an internal method may not access private members.

Preconditions and postconditions should also not throw exceptions.

Virtual methods and interface methods may have preconditions and postconditions, in which case the compiler guarantees that overrides and implementations of these methods satisfy the preconditions. To make this clear to a developer reading the code, the override or interface implementation would state “requires base” or “ensures base”, to indicate that there are imposed constraints, while not forcing the developer writing the code to explicitly type them out.

interface IItemCollection
{
    int Count ensures return >= 0 { get; }
    …
}

class MyItemCollection : IItemCollection
{
    public int Count ensures base => m_count;
    …
}

Alternatives: Fail fast vs exceptions

In support of migrating existing code to use contracts, or for places where an exception is really desired over fail fast, we could optionally consider additional syntax to specify that an exception should be thrown instead of fail fasting.

For example, the previous Insert example’s requires and ensures clauses would result in fail fasting if a condition isn’t met:

public int Insert(T item, int index)
    requires index >= 0 && index <= Count
    ensures return >= 0 && return < Count
{
    return InsertCore(item, index);
}

But, the developer could explicitly override the fail fast by specifying what should happen in case of failure:

public int Insert(T item, int index)
    requires index >= 0 && index <= Count else throw new ArgumentOutOfRangeException(nameof(index))
    ensures return >= 0 && return < Count
{
    return InsertCore(item, index);
}

Issue Analytics

  • State:closed
  • Created 9 years ago
  • Reactions:132
  • Comments:259 (57 by maintainers)

github_iconTop GitHub Comments

15reactions
iam3yalcommented, Jun 8, 2016

@jaredpar is there anything new in this space? will we ever see this as part of the language? I know it won’t be part of C# 7 but is there any progress in this area? like discussions? different way to tackle this? what are your thoughts?

12reactions
aarondandycommented, Jan 28, 2015

Any possibility of getting invariants as well?

Would love to see the static analysis tools we have in Code Contracts working with these new contracts.

I really like the presented syntax to decide between exceptions and fail-fast for preconditions.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Writing A Contract Proposal: Everything You Need to Know
There are several elements to a contract proposal, which include: The situation at hand; Project goals; Recommended methodology; Project time; Project cost ...
Read more >
Contract Proposal: What is it & How to Create it? - Bit Blog - Bit.ai
Contract proposal is a proposal made by one business with the aim of entering into a contractual relationship with another business or customer...
Read more >
15.404-1 Proposal analysis techniques.
The objective of proposal analysis is to ensure that the final agreed-to price is fair and reasonable. (1) The contracting officer is responsible...
Read more >
RFP: What a Request for Proposal Is, Requirements, and ...
A request for proposal (RFP) is a business document that announces a project, describes it, and solicits bids from qualified contractors to complete...
Read more >
Proposal vs Contract - What Are the Main Differences?
In a way, a proposal is the foundation of a contract. There can be no contract without a business proposal. One party proposes...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found