{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/13553","repository_url":"https://api.github.com/repos/dotnet/roslyn","labels_url":"https://api.github.com/repos/dotnet/roslyn/issues/13553/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/13553/comments","events_url":"https://api.github.com/repos/dotnet/roslyn/issues/13553/events","html_url":"https://github.com/dotnet/roslyn/issues/13553","id":174671219,"number":13553,"title":"Proposal: Alternative to DbC","user":{"login":"eyalsk","id":3756641,"avatar_url":"https://avatars.githubusercontent.com/u/3756641?v=3","gravatar_id":"","url":"https://api.github.com/users/eyalsk","html_url":"https://github.com/eyalsk","followers_url":"https://api.github.com/users/eyalsk/followers","following_url":"https://api.github.com/users/eyalsk/following{/other_user}","gists_url":"https://api.github.com/users/eyalsk/gists{/gist_id}","starred_url":"https://api.github.com/users/eyalsk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eyalsk/subscriptions","organizations_url":"https://api.github.com/users/eyalsk/orgs","repos_url":"https://api.github.com/users/eyalsk/repos","events_url":"https://api.github.com/users/eyalsk/events{/privacy}","received_events_url":"https://api.github.com/users/eyalsk/received_events","type":"User","site_admin":false},"labels":[{"id":169838071,"url":"https://api.github.com/repos/dotnet/roslyn/labels/Area-Language%20Design","name":"Area-Language Design","color":"5319e7","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":34,"created_at":"2016-09-02T03:08:02Z","updated_at":"2016-12-12T18:03:04Z","closed_at":null,"body":"This is in response to @MadsTorgersen reply on the [.NET blog](https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/)\n\n> Nothing on design by contract this time around, and I’m not sure if there will be anytime soon. We’ve looked a lot at contract-style features, and they tend to get quite verbose and complicated. I am not sure that they would carry their weight in added value as language features. But maybe, one day, if we can get the design right.\n> \n> While people do use CodeContracts for many things, the 90% case seems to be dealing with null. We are eager to tackle the language integration of that in a more type-system-oriented way, allowing you to distinguish between nullable and nonnullable reference types and track correct usage based on that. I hope this can happen in the next major release of C#.\n\nI partly agree with Mads that DbC tends to be verbose and sometimes complicated but this 10% are as useful as solving the null problems.\n### Problem:\n\nChecking the input and the output of each method can be both pretty nasty and daunting task for few reasons:\n1. **API** - There is no standard API or way to express it in the language and because of that it's harder to build static analyzers that understand our code in a way that it can prove or disprove reliably the assumptions that we make and give us feedback about it.\n2. **Testing** - Testing is expensive, people shouldn't write tests that a tool can make it a lot better, in fact, as an example if we take CodeContracts it did many things right beyond providing this \"standard\" way of writing contracts at the API level, we had control over many things including great static analysis so yeah we traded complexity and verbosity with data validation.\n   \n   Back then when the CodeContracts project was under active development I used it heavily and I saved a lot of time by not writing these validation tests, some people will disagree with me on that mostly TDD purist but that's fine.\n   \n   We might not cover everything through tests and we might not even write the correct tests and sometimes we might even forget to write tests so it's better to have a feature that will always be there and do it for us.\n3. **Visibility** - We have no way to know what the method accept and what the method rejects which will probably lead to some failures so we end up looking it up in the documentation, the code itself or in the tests but these things aren't immediate and sometimes you don't even have them available so you have to do some experiments or decompile the code.\n\nPeople don't add contracts at all because there's too much weight on the programmer so people don't deal with it at all, they don't care what people will pass to their functions and when I ask them \"Why they don't do it?\" the response I get is \"It's too much work\" I don't really accept these responses but I know that if there was a way to express it in the language and the compiler was statically analyzing these contracts people would use it a lot because no one likes to do mistakes and waste their time.\n### Solution:\n\nNow I know that the null problem is already [covered](https://github.com/dotnet/roslyn/tree/features/NullableReferenceTypes/docs/features/NullableReferenceTypes) so I'm not speaking about it here at all.\n\nThis solution aims to solve cases where we don't want to create a custom type but just want to restrict the input.\n\nSo the way it works is by annotate parameters that will be evaluated by the compiler or Roslyn at post-compile-time.\n\nSomething like this:\n\n```\nvoid Time(\n    [RangeContract(1, 12)] int hour, \n    [RangeContract(1, 60)] int min, \n    [RangeContract(1, 60)] int sec, \n    [RegexContract(\"^(p|a)m$\")] string period) {\n}\n```\n\nNow these contract attributes are not really special but they have to derive from `ContractAttribute` so the compiler would be aware of this and when you do derive from this you have to implement the `IsValid` method.\n\n```\nabstract class ContractAttribute : Attribute {}\n\nclass RangeContractAttribute : ContractAttribute\n{\n    public RangeContractAttribute(int from, int to)\n    {\n    }\n\n    public bool IsValid(int value)\n    {\n        return true;\n    }\n}\n\nclass RegexContractAttribute : ContractAttribute\n{\n    public RegexContractAttribute(string regex)\n    {\n    }\n\n    public bool IsValid(string value)\n    {\n        return true;\n    }\n}\n```\n\nI'm aware that `ContractAttribute` lack the `IsValid` method above but that's because attributes does not support generics so `ContractAttribute` is purely a _marker_.\n\nThe value that is passed as arguments to the `Time` method is passed to the `IsValid` method for validation and is executed by the compiler and the way this will work is I imagine the compiler will have to sometimes compile fragment(s) of the code to get the value.\n\nThere should be a message property that returns a message in cases that the contract failed.\n\nWe can even go further with this and have the compiler treat contracts like attributes so instead of writing the full name `RangeContract` we can just write `Range`.\n\nMaybe, as an option, it's even possible to force these contracts at run-time by allowing the compiler to generate some code that calls the IsValid method.\n\nThis approach is fully extensible so we can plug into it.\n\nP.S. Don't be hard one me when it comes to terminologies of some of the things in my post and by all means feel free to correct me, after all I'm not a compiler person (even though I'm learning it) but I do want the tools I use to improve the code I write and the code others write.\n\n**Edit:** Change `StringContract` to `RegexContract`.\n"},"comment":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/comments/266504002","html_url":"https://github.com/dotnet/roslyn/issues/13553#issuecomment-266504002","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/13553","id":266504002,"user":{"login":"JamesFaix","id":12615512,"avatar_url":"https://avatars.githubusercontent.com/u/12615512?v=3","gravatar_id":"","url":"https://api.github.com/users/JamesFaix","html_url":"https://github.com/JamesFaix","followers_url":"https://api.github.com/users/JamesFaix/followers","following_url":"https://api.github.com/users/JamesFaix/following{/other_user}","gists_url":"https://api.github.com/users/JamesFaix/gists{/gist_id}","starred_url":"https://api.github.com/users/JamesFaix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JamesFaix/subscriptions","organizations_url":"https://api.github.com/users/JamesFaix/orgs","repos_url":"https://api.github.com/users/JamesFaix/repos","events_url":"https://api.github.com/users/JamesFaix/events{/privacy}","received_events_url":"https://api.github.com/users/JamesFaix/received_events","type":"User","site_admin":false},"created_at":"2016-12-12T18:03:03Z","updated_at":"2016-12-12T18:03:03Z","body":"I've started trying to implement DbC using Roslyn's syntax rewriters.  https://github.com/JamesFaix/Traction"}}
{"actor":{"display_login":"JamesFaix"}}