34

(Also posted on the MSDN forum - but that doesn't get much traffic, as far as I can see.)

I've been trying to provide an example of Assert and Assume. Here's the code I've got:

public static int RollDice(Random rng)
{
    Contract.Ensures(Contract.Result<int>() >= 2 &&
                     Contract.Result<int>() <= 12);

    if (rng == null)
    {
        rng = new Random();
    }
    Contract.Assert(rng != null);

    int firstRoll = rng.Next(1, 7);
    Contract.Assume(firstRoll >= 1 && firstRoll <= 6);

    int secondRoll = rng.Next(1, 7);
    Contract.Assume(secondRoll >= 1 && secondRoll <= 6);

    return firstRoll + secondRoll;
}

(The business about being able to pass in a null reference instead of an existing Random reference is purely pedagogical, of course.)

I had hoped that if the checker knew that firstRoll and secondRoll were each in the range [1, 6], it would be able to work out that the sum was in the range [2, 12].

Is this an unreasonable hope? I realise it's a tricky business, working out exactly what might happen... but I was hoping the checker would be smart enough :)

If this isn't supported now, does anyone here know if it's likely to be supported in the near-ish future?

EDIT: I've now found that there are very complicated options for arithmetic in the static checker. Using the "advanced" text box I can try them out from Visual Studio, but there's no decent explanation of what they do, as far as I can tell.

Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
  • Jon, have you tried contacting the guys from DevLabs directly? You will find the team members listed at the bottom of this page: http://research.microsoft.com/en-us/projects/contracts/ – Dirk Vollmar Aug 07 '09 at 11:53
  • And their e-mail address is codconfb _at_ microsoft _dot_ com (as mentioned on the same page). I would be interested to know the answer to your question. – Dirk Vollmar Aug 07 '09 at 11:54
  • I thought it would be a bit more polite to ask questions in the forum first... if I don't hear back on the forums or here, I'll ask by email too. – Jon Skeet Aug 07 '09 at 12:04
  • Just as a side issue: does this look like a reasonable example? – Jon Skeet Aug 07 '09 at 12:08
  • I agree Jon, although I feel that there is no user base (yet) for this rather new tool. And btw, your sample seems quite reasonable to me. – Dirk Vollmar Aug 07 '09 at 15:32
  • Glad the sample looks okay - have emailed the team now (with 4 questions). I think the user base needs to be kick-started a bit, which is something I'm hoping to do with the book. – Jon Skeet Aug 07 '09 at 15:57
  • As you include it in your book I am wondering whether Code Contracts will be part of .NET 4.0? It wasn't part of the CTP afaik and I couldn't find any other information except that it is only free with an academic license. – Dirk Vollmar Aug 07 '09 at 16:24
  • @divo: The core libraries are part of .NET 4.0 (in mscorlib) but the tools aren't (currently). They're a free download, but you only get the static checker if you've got Team System installed, I believe. – Jon Skeet Aug 07 '09 at 16:51
  • 2
    Jon, so the static checker will not be in regular VS 2010? If so, then we might as well not have contracts, as not everyone uses the team system. – Joan Venge Aug 07 '09 at 17:45
  • 2
    @Joan: You're assuming that code contracts have no value without static checking. I disagree with that assumption. – Jon Skeet Aug 11 '09 at 08:22

2 Answers2

14

I've had an answer on the MSDN forum. It turns out I was very nearly there. Basically the static checker works better if you split out "and-ed" contracts. So, if we change the code to this:

public static int RollDice(Random rng)
{
    Contract.Ensures(Contract.Result<int>() >= 2);
    Contract.Ensures(Contract.Result<int>() <= 12);

    if (rng == null)
    {
        rng = new Random();
    }
    Contract.Assert(rng != null);

    int firstRoll = rng.Next(1, 7);
    Contract.Assume(firstRoll >= 1);
    Contract.Assume(firstRoll <= 6);
    int secondRoll = rng.Next(1, 7);
    Contract.Assume(secondRoll >= 1);
    Contract.Assume(secondRoll <= 6);

    return firstRoll + secondRoll;
}

That works without any problems. It also means the example is even more useful, as it highlights the very point that the checker does work better with separated out contracts.

Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
1

I don't know about the MS Contracts Checker tool, but range analysis is a standard static analysis technique; it is widely used in commercial static analysis tools to verify that subscript expressions are legal.

MS Research has a good track record at this kind of static analysis, and so I'd expect doing such range analysis to be a goal of the Contracts Checker, even if not presently checked.

Ira Baxter
  • 88,629
  • 18
  • 158
  • 311