{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/119","labels_url":"https://api.github.com/repos/dotnet/roslyn/issues/119/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/119/comments","events_url":"https://api.github.com/repos/dotnet/roslyn/issues/119/events","html_url":"https://github.com/dotnet/roslyn/issues/119","id":55792425,"number":119,"title":"Proposal: Method Contracts","user":{"login":"stephentoub","id":2642209,"avatar_url":"https://avatars.githubusercontent.com/u/2642209?v=3","gravatar_id":"","url":"https://api.github.com/users/stephentoub","html_url":"https://github.com/stephentoub","followers_url":"https://api.github.com/users/stephentoub/followers","following_url":"https://api.github.com/users/stephentoub/following{/other_user}","gists_url":"https://api.github.com/users/stephentoub/gists{/gist_id}","starred_url":"https://api.github.com/users/stephentoub/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stephentoub/subscriptions","organizations_url":"https://api.github.com/users/stephentoub/orgs","repos_url":"https://api.github.com/users/stephentoub/repos","events_url":"https://api.github.com/users/stephentoub/events{/privacy}","received_events_url":"https://api.github.com/users/stephentoub/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/dotnet/roslyn/labels/1%20-%20Planning","name":"1 - Planning","color":"cccccc"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Area-Language%20Design","name":"Area-Language Design","color":"5319e7"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Feature%20Request","name":"Feature Request","color":"fc2929"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Language-C%23","name":"Language-C#","color":"207de5"}],"state":"open","locked":false,"assignee":{"login":"MadsTorgersen","id":6677272,"avatar_url":"https://avatars.githubusercontent.com/u/6677272?v=3","gravatar_id":"","url":"https://api.github.com/users/MadsTorgersen","html_url":"https://github.com/MadsTorgersen","followers_url":"https://api.github.com/users/MadsTorgersen/followers","following_url":"https://api.github.com/users/MadsTorgersen/following{/other_user}","gists_url":"https://api.github.com/users/MadsTorgersen/gists{/gist_id}","starred_url":"https://api.github.com/users/MadsTorgersen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MadsTorgersen/subscriptions","organizations_url":"https://api.github.com/users/MadsTorgersen/orgs","repos_url":"https://api.github.com/users/MadsTorgersen/repos","events_url":"https://api.github.com/users/MadsTorgersen/events{/privacy}","received_events_url":"https://api.github.com/users/MadsTorgersen/received_events","type":"User","site_admin":false},"milestone":null,"comments":41,"created_at":"2015-01-28T18:05:13Z","updated_at":"2015-02-12T23:05:33Z","closed_at":null,"body":"(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.)\r\n\r\n## Background\r\n\"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.\r\n```C#\r\npublic int Insert(T item, int index)\r\n{\r\n    Contract.Requires(index >= 0 && index <= Count);\r\n    Contract.Ensures(Contract.Result<int>() >= 0 && Contract.Result<int>() < Count);\r\n    return InsertCore(item, index);\r\n}\r\n```\r\n\r\n## Problem\r\nVery 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).\r\n\r\n## Solution: Language support for method contracts\r\nBasic 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. \r\n\r\nThe 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.\r\n```C#\r\npublic int Insert(T item, int index)\r\n    requires index >= 0 && index <= Count\r\n    ensures return >= 0 && return < Count\r\n{\r\n    return InsertCore(item, index);\r\n}\r\n```\r\nThese 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.\r\n\r\nUnlike .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.\r\n\r\nThe 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.\r\n\r\nPreconditions and postconditions should also not throw exceptions.\r\n\r\nVirtual 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.\r\n```C#\r\ninterface IItemCollection\r\n{\r\n    int Count ensures return >= 0 { get; }\r\n    …\r\n}\r\n    \r\nclass MyItemCollection : IItemCollection\r\n{\r\n    public int Count ensures base => m_count;\r\n    …\r\n}\r\n```\r\n\r\n## Alternatives: Fail fast vs exceptions\r\nIn 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.\r\n\r\nFor example, the previous Insert example's requires and ensures clauses would result in fail fasting if a condition isn't met:\r\n```C#\r\npublic int Insert(T item, int index)\r\n    requires index >= 0 && index <= Count\r\n    ensures return >= 0 && return < Count\r\n{\r\n    return InsertCore(item, index);\r\n}\r\n```\r\nBut, the developer could explicitly override the fail fast by specifying what should happen in case of failure:\r\n```C#\r\npublic int Insert(T item, int index)\r\n    requires index >= 0 && index <= Count else throw new ArgumentOutOfRangeException(nameof(index))\r\n    ensures return >= 0 && return < Count\r\n{\r\n    return InsertCore(item, index);\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/comments/74173103","html_url":"https://github.com/dotnet/roslyn/issues/119#issuecomment-74173103","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/119","id":74173103,"user":{"login":"jaredpar","id":146967,"avatar_url":"https://avatars.githubusercontent.com/u/146967?v=3","gravatar_id":"","url":"https://api.github.com/users/jaredpar","html_url":"https://github.com/jaredpar","followers_url":"https://api.github.com/users/jaredpar/followers","following_url":"https://api.github.com/users/jaredpar/following{/other_user}","gists_url":"https://api.github.com/users/jaredpar/gists{/gist_id}","starred_url":"https://api.github.com/users/jaredpar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jaredpar/subscriptions","organizations_url":"https://api.github.com/users/jaredpar/orgs","repos_url":"https://api.github.com/users/jaredpar/repos","events_url":"https://api.github.com/users/jaredpar/events{/privacy}","received_events_url":"https://api.github.com/users/jaredpar/received_events","type":"User","site_admin":false},"created_at":"2015-02-12T23:05:32Z","updated_at":"2015-02-12T23:05:32Z","body":"@fschmied \r\n\r\n> They are not provided as a way to continue execution in a broken state. They are instead meant as a means to terminate execution of the current \"operation\", falling back the call stack up to a safe location, where the application can decide what to do about that unexpected error. \r\n\r\nThis is the root of the disagreement.  How can the application make an educated decision that it is a safe location?  The application has identified that the code it is calling has a coding error in it.  That is all it knows.  \r\n\r\nIt has no understanding of why this failure occurred, if the code was left in a recoverable state or really even what component the failure came from.  The error could have occurred directly in the code that was called or even transitive dependencies.  The argument exception could be anything from a negative index to passing unsatized user input to a back end.  There is just no way of knowing.  \r\n\r\nThe application simply cannot make an informed decision on whether or not it is safe to continue executing.  This is why termination is the best option.  \r\n\r\n\r\n\r\n\r\n"}}