Runtime: Make use of Code Contracts where ever applicable.

Created on 22 Jan 2015  路  14Comments  路  Source: dotnet/runtime

I wonder the reason why while the code contracts are part of BCL and it is a research project of Microsoft, only some of the API makes use of it. This this is effectively preventing making use of code contracts for the end consumers as well.
I would appreciate at least if you can make use of Code Contracts on the public surface API.

area-Meta enhancement

Most helpful comment

Since the C# team started to talk about code contract support in the language (see https://github.com/dotnet/roslyn/issues/98), I would really like to wait with library contracts till we know what the C# team will do here.

All 14 comments

Absolutely agree. I think the answer is BCL was created before CC API and only newest code embrace it. It would be nice to have it used instead all those null params checking etc.

I'd like to help with this if the maintainers consider it useful.

+1 for helping.

I'd be willing to give a hand with this too.
This has already come up to some extent where somebody was complaining that the immutable collections didn't guarantee a non-null return from an add(...) (although this appears to have been because the static analysis isn't being run/exported, as the contracts are actually present in the code).

Note that because I imagine there are some cases where you want to be able to differentiate between runtime and compile time checks (and that I'm not sure you can require consumers to be using code contracts for something this widely distributed), some runtime checks would still be required.

Before jumping into this I have a few questions and comments:

  1. What do people actually do with code contracts in their libraries and apps? Are you guys running the static analysis tools?
  2. We cannot change our code to actually use the rewriter and actually turn these into runtime failures because we have well defined guidelines of what exceptions to throw and cannot just start throwing ContractException's as it would be a breaking change. This code is much older than Code Contracts are.
  3. Adding these into the implementation assemblies for .NET Core would only act as a hint for people actually reading the code, as people don't actually compile directly against these implementation assemblies. We have a notion of multi-targeting which means for the majority of our libraries we have reference assemblies (i.e. assemblies without any IL only metadata) and they don't and cannot contain these code contracts as they aren't part of the metadata they are part of the IL.

For these reasons there isn't a lot of value in adding them to all the .NET Core libraries, but I'm curious to see what others think.

@weshaggard
1.some of us do.

  1. Not necessarily. You can easily control the exception. Code contracts also support if-then throw style code.
  2. I don't understand what you mean.

@weshaggard Re 3. I thought that's what Contract Reference Assemblies are for. Though I have no idea if it would make sense or even be possible to distribute those alongside normal reference assemblies.

In regard to 2 - There's cases where it would be good to have compile-time checks, but _not_ have them rewritten into run-time checks.
The specific case I'm thinking of is buried in the implementation of ImmutableArray:

/// <summary>
/// Gets the element at the specified index in the read-only list.
/// </summary>
/// <param name="index">The zero-based index of the element to get.</param>
/// <returns>The element at the specified index in the read-only list.</returns>
public T this[int index]
{
    get
    {
        // We intentionally do not check this.array != null, and throw NullReferenceException
        // if this is called while uninitialized.
        // The reason for this is perf.
        // Length and the indexer must be absolutely trivially implemented for the JIT optimization
        // of removing array bounds checking to work.
        return this.array[index];
    }
}

... a number of the tests for this class pop analysis errors because the static checks can't determine information about the underlying array. Clearly, you'd want to put in the static checks (say, Requires(index >= 0 && index < this.array.length), which gives the static tool the necessary information), but given these comments (and some of the others, in this instance), you wouldn't want them turned into runtime checks.
There's the System.Diagnostics.Requires (?) run-time checks (eg, NotNull, NotNullAllowStructs, etc), which could be used to explicitly create run-time checks (instead of having contracts turned into run-time checks). I haven't been able to figure out if the methods in that class were decorated with the ContractArgumentValidator attribute, which would mean they'd also supply static verification, too...

(my read of the ContractRuntimeIgnored attribute is that its use would be on this[index], not on any contracts inside that method. To get it to disable runtime checks, you'd somehow need to get it into the definition for arrays which 1. I'm not sure is possible, and 2. would prevent anybody from using runtime checks on arrays, which would be a larger problem. Code Contracts don't seem to have a fine enough grain to be able to prevent specific contracts from being converted to runtime...)

Since the C# team started to talk about code contract support in the language (see https://github.com/dotnet/roslyn/issues/98), I would really like to wait with library contracts till we know what the C# team will do here.

@KrzysztofCwalina - That appears to be prelim discussion for 7, and we're not really even to 6 yet. No guarantee it'll even make it into 7...
How long until such a feature would be available? Exporting contract reference assemblies is more about making something available "now"-ish.

@ReverseBlade Yes there are some ways to control the exceptions but it still doesn't work in a number of the cases, without potentially breaking compat. If we were to add code contract information in our libraries we would mostly end up with Contract.EndContractBlock() after our argument validation. As for bullet 3 for the core libraries people do not build against the implementation of a library they build against a reference assembly. A reference assembly is just an assembly that contains only the definitions (think C++ header file) and doesn't contain any of the code (aka IL), and code contracts actually are part of the code and not the definitions.

@svick those contract reference assemblies were manually produced for some of the full .NET framework libraries which are not the same for .NET Core. Those were produced by the team that was working on the code contract tools and on the core framework team we currently don't have a good process to produce those.

So without an easy way to provide code contracts in the API definitions in the reference assembly and without support for tools (static checker and ccrewrite) for .NETCore there isn't much value in adding the code contracts in our core implementation libraries themselves.

The best solution here would be for the compiler to support code contracts as a notion as @KrzysztofCwalina points out, which would give this first class support and be more useful.

I'm going to close this for now.

@weshaggard outlines our general feelings here. In short, the overhead of adopting contracts for our team outweighs the benefits. We don't want to take a dependency on the code contracts rewriter, which prevents us from using post conditions, and the gymnastics to adopt preconditions in a compatible way doesn't feel worth the cost at the time.

This doesn't mean we dislike the idea of code contracts. Many members of the team (myself included) love contracts and would love to see first class adoption across both C# and VB. We plan to use the open design process of Roslyn to propose new features for contracts in the language.

[Our company Microsoft consultant Ben Gimblett pointed me to this thread when we discovered that we had to rip out contact checks to port our code to .Net Core]

@weshaggard [commented on Jan 23 2015] "1.What do people actually do with code contracts in their libraries and apps"

In our product:

  • We use code contracts for all our interfaces (hundreds)
  • We use code contracts for many internal and private methods (thousands and thousand)
  • It is not unusual for a method to have 6+ requires/ensures contracts checks
  • We use object invariant (tens and tens)
  • We use them for their purpose - in debug only to check that the caller is obeying their side of the contract and as a poor man's version of stronger typing. The classic (theoretical) example would be an operation which operates on temperature but we don't want to define a new type, but want to protect against temperatures lower than absolute zero being passed in.

"overhead of adopting contracts for our team outweighs the benefits"
To you may be. Certainly not to us. This has just raised the cost of porting our significant server product to Core by a non-trivial amount.

"We plan to use the open design process of Roslyn to propose new features for contracts in the language."
Way, way, way, too slow. Yes, it should have been done in the language in the first place, but that does not mean you should leave us high and dry.

Why can't we have contracts working on Core?

boo

Matt

@Mattacks to be clear my comments are more around applying code contracts to the .NET Core libraries themselves. The actual Code Contract APIs do exist in .NET Core so there shouldn't be any issue in porting code but there aren't any static analysis tools for them that work on .NET Core. Those tools were written by some researchers which aren't really getting much attention (see https://github.com/microsoft/codecontracts) if you would like to have the tools supported the conversation would best be had over there.

Was this page helpful?
0 / 5 - 0 ratings