On Friday, November 03, 2017 02:08:43 codephantom via Digitalmars-d wrote: > On Thursday, 2 November 2017 at 18:40:26 UTC, bauss wrote: > > I disagree with that, because it would make the language very > > verbose. > > Personally, I think function headers are starting to become to > verbose. > > I don't believe removing the separate scaffolding that > accompanies contracts, so that you incorporate contracts directly > into the scaffolding of a function header is a good design choice. > > There was an inital design choice to put in that scaffolding for > contracts, and presumably it was done so for a reason. I didn't > see that discussed in the DIP.
They're designed so that you can run more or less arbitrary code, and for that having normal blocks like in, out, and invariant currently do makes a lot of sense. The issue is that if you just need something short - especially if you're just asserting some conditions and not running any other code to set up the assertions - then they get awfully verbose for what they're doing. So, having a terser syntax for simpler contracts is desirable. Personally, I hate how verbose they are, but my solution is just not to use them. And IMHO, the only place that they add real value is in classes, where their success or failure can be &&ed or ||ed based on how that should work with inheritance. For struct member functions or free functions, where no inheritance is involved, they add considerably less value. in contracts for functions that aren't members of classes can just be done at the beginning of the function, and you don't lose anything. If some aspect of the contracts were checked at compile time, or if whether contracts were run or not depended on how the caller was compiled rather than the callee, then having an explicit in contract could be useful. But as it stands, they really don't add anything over simply asserting at the beginning of the function (except in the case where inheritance is involved). out contracts IMHO are almost universally useless for pretty much the same reason that unittest blocks that are compiled into templates are almost universally useless: they have to be so generic that in most cases, you can't do much with them. It almost always works far better to test the result of functions by using unit tests to test that known inputs give the correct results. Pretty much the only case where out contracts work well is when you have a very specific, testable condition that all results must have and which does not depend on the input, and most functions simply don't work that way. And while invariants are of some value for classes, IMHO, they should be avoided like the plague in structs. The problem is that _every_ public function (including opAssign) has the invariant called before and after. That means if you ever try and do anything with void initialization for performance, you're screwed if you have an invariant, because whatever garbage is in the member variables will be tested as soon as you try to assign a valid value to the object. If it just tested _after_ opAssign, then that would be fine, but it tests before as well. And it may actually be that if emplace is involved (e.g. with an allocator) that initializing a class with an invariant could have the same problem. So, much as I think that invariants could add real value (certainly, they're far less verbose than manually adding those same checks to ever public member function), I never use them. So, while I really don't like how verbose contracts in D are, and I wouldn't mine a more concise syntax, I also find it hard to care, because I'm not going to use them either way. - Jonathan M Davis
