June 23, 2017
On 6/23/17 3:51 PM, Moritz Maxeiner wrote:
> On Friday, 23 June 2017 at 18:42:55 UTC, Steven Schveighoffer wrote:
>> On 6/23/17 2:24 PM, Moritz Maxeiner wrote:
>>> I'm all for this syntax, just one spec/implementation question:
>>> If the new contract syntax (formally) shares grammar rules with assert, won't that cause more work for people who want to update the assert syntax later (since they will have to take contracts into account)?
>>
>> No. Asserts are the meat of in/out contracts, these are actually asserts. Anything you do to the assert grammar should be done here as well.
> 
> I'm not sure I get what you mean here: Asserts are just one possible implementation of contract checking; this new syntax explicitly decouples contract specification from contract checking (semantics), opening the way for future DIPs addressing such things as changing contract checking from assert to a different system and/or moving contract checking from the callee to the caller transparently. My worry is that having  contract specification and contract implementation share grammar rules leaves them artificially coupled, though I don't know enough about the compiler internals to know for sure: That's the essence of my question.

Moving the check from the callee to the caller wouldn't matter here, it just defines when the asserts are called.

I don't think there's an issue here -- you can implement some other form of checking if you wish, but it's going to be outside the language.

You can always still do in and out block syntax. Or is this DIP proposing to do away with that? I didn't see any mention of deprecating current syntax.

I view this improvement like short lambda syntax. When your lambda is one expression, so much easier and convenient to use the => form. But you can always reach for the multi-statement form if needed.

-Steve
June 23, 2017
On Friday, 23 June 2017 at 20:03:17 UTC, Moritz Maxeiner wrote:
>>> No. Asserts are the meat of in/out contracts, these are actually asserts. Anything you do to the assert grammar should be done here as well.
>>
>> I agree. I can understand wanting to pass in/out violations to a different handler behind the scenes. But I don't see why that should affect the grammar.
>
> Because coupling the new contract syntax and assert syntax in the grammar means that changing assert syntax will affect the new contract syntax (when it shouldn't, as they are semantically decoupled).

By default, I assume they will not be semantically decoupled, that they will all just use regular asserts. I think the consistency the assert grammar will bring is worth a whole lot, as once it is understood in one place, it is understood everywhere. That's why it's so easy for Timon to implement, for example, because the assert logic is already available. So, for me to be convinced that the the grammar for in/out contracts should be different, I'd have to see a clear and compelling use case. What exactly did you have in mind? My naive assumption is that any improvement in the in/out grammar would also apply to asserts, and vice versa. I would go further and say that having consistency among all types of contracts is valuable enough to be worth sacrificing a considerable amount of flexibility in the grammar, even if a compelling use case were presented.
June 23, 2017
On Fri, Jun 23, 2017 at 04:15:38PM -0400, Steven Schveighoffer via Digitalmars-d wrote: [...]
> You can always still do in and out block syntax. Or is this DIP proposing to do away with that? I didn't see any mention of deprecating current syntax.
> 
> I view this improvement like short lambda syntax. When your lambda is one expression, so much easier and convenient to use the => form. But you can always reach for the multi-statement form if needed.
[...]

Yes, this is also my understanding: the current syntax will be retained (hence, no breakage of current code), but a new syntax better suited for short contracts will be introduced. I think this is the right way to go.


T

-- 
It won't be covered in the book. The source code has to be useful for something, after all. -- Larry Wall
June 23, 2017
On Friday, 23 June 2017 at 20:27:58 UTC, MysticZach wrote:
> On Friday, 23 June 2017 at 20:03:17 UTC, Moritz Maxeiner wrote:
>>>> No. Asserts are the meat of in/out contracts, these are actually asserts. Anything you do to the assert grammar should be done here as well.
>>>
>>> I agree. I can understand wanting to pass in/out violations to a different handler behind the scenes. But I don't see why that should affect the grammar.
>>
>> Because coupling the new contract syntax and assert syntax in the grammar means that changing assert syntax will affect the new contract syntax (when it shouldn't, as they are semantically decoupled).
>
> By default, I assume they will not be semantically decoupled, that they will all just use regular asserts. I think the consistency the assert grammar will bring is worth a whole lot, as once it is understood in one place, it is understood everywhere. That's why it's so easy for Timon to implement, for example, because the assert logic is already available. So, for me to be convinced that the the grammar for in/out contracts should be different, I'd have to see a clear and compelling use case. What exactly did you have in mind?

Normal usage of the new syntax? If asserts later on get a (possibly breaking) syntax overhaul that will affect (and forward breakage to) the contract syntax, as well, if it uses the same compiler infrastructure.

> My naive assumption is that any improvement in the in/out grammar would also apply to asserts, and vice versa.

Why should it? Contracts are not asserts or vice versa.

> I would go further and say that having consistency among all types of contracts is valuable enough to be worth sacrificing a considerable amount of flexibility in the grammar, even if a compelling use case were presented.

I'm not sure what you're getting at here. With the proposal Timon implemented we have the following:
- The older, flexible contract syntax, which essentially only provides contract "shells" that you have to fill with your own preferred contract implementation (for which asserts are typically used)
- the newer, decoupled contract syntax that separates contract specification and implementation from each other; Timon's implementation uses asserts as the internal contract implementation AFAIK
- Asserts as a D builtin for condition checking (*not* a type of contract)

In any case, it's merely a concern about future work load. If asserts receive an overhaul, whoever does that will have to (potentially) deal with it, I guess.
June 23, 2017
On Friday, 23 June 2017 at 20:49:35 UTC, Moritz Maxeiner wrote:
> Normal usage of the new syntax? If asserts later on get a (possibly breaking) syntax overhaul that will affect (and forward breakage to) the contract syntax, as well, if it uses the same compiler infrastructure.

I believe this fear is irrational. A breaking change to the assert syntax would be extremely stupid. Imagine how much code would break if there were a breaking change to `assert`! The only possible changes to it must be additive.

>> My naive assumption is that any improvement in the in/out grammar would also apply to asserts, and vice versa.
>
> Why should it? Contracts are not asserts or vice versa.

I 95% disagree. As far as I can tell, they are _very_ similar. The only difference I can see is that when you violate an `in` contract, the exit message should point to the caller instead of the callee as the source of the problem. Beyond that, they seem like little more than glorified `assert`s. I think their greatest benefit is in helping the programmer read and understand the logic of the program, rather than in anything the compiler can do with them.

> I'm not sure what you're getting at here. With the proposal Timon implemented we have the following:
> - the newer, decoupled contract syntax that separates contract specification and implementation from each other; Timon's implementation uses asserts as the internal contract implementation AFAIK

Not exactly. It actually _couples_ `in` expressions with assert expressions. In essence it just lowers

int fun(int a)
in(a)
{
}

...to:

int fun(int a)
in { assert(a); }
{
}

This is a sensible default. In the future, some logic could be added to provide a hook to a different implementation of the `in` function, so that it would lower instead to:

int fun(int a)
in { __userDefinedInContract(a); }
{
}

But I suspect the vast majority will stick with the default.

June 23, 2017
On Friday, 23 June 2017 at 21:14:47 UTC, MysticZach wrote:
> On Friday, 23 June 2017 at 20:49:35 UTC, Moritz Maxeiner wrote:
>> Normal usage of the new syntax? If asserts later on get a (possibly breaking) syntax overhaul that will affect (and forward breakage to) the contract syntax, as well, if it uses the same compiler infrastructure.
>
>>> My naive assumption is that any improvement in the in/out grammar would also apply to asserts, and vice versa.
>>
>> Why should it? Contracts are not asserts or vice versa.
>
> I 95% disagree. As far as I can tell, they are _very_ similar. The only difference I can see is that when you violate an `in` contract, the exit message should point to the caller instead of the callee as the source of the problem. Beyond that, they seem like little more than glorified `assert`s.

This is (unfortunately) not a matter of opinion (within the context of DbC), see Meyer's original publication [1], who effectively birthed and established the DbC paradim.
Contracts within the DbC paradigm *are* abstractions that do not necessitate any particular implementation. Most native languages simply (sensibly) choose to use asserts for that.

>
>> I'm not sure what you're getting at here. With the proposal Timon implemented we have the following:
>> - the newer, decoupled contract syntax that separates contract specification and implementation from each other; Timon's implementation uses asserts as the internal contract implementation AFAIK
>
> Not exactly. It actually _couples_ `in` expressions with assert expressions. In essence it just lowers
>

It would only couple the contracts with asserts if the DIP also specifies that asserts *must* be used for the lowering (which I would be against btw).
Otherwise, it couples contracts with the request of "you take care of the implementation for me", which Timon's dmd implementation just happens to be use asserts for as the default (which is fine).

[1] Meyer, Bertrand: Design by Contract, Technical Report TR-EI-12/CO, Interactive Software Engineering Inc., 1986
June 24, 2017
On Friday, 23 June 2017 at 21:14:47 UTC, MysticZach wrote:
> On Friday, 23 June 2017 at 20:49:35 UTC, Moritz Maxeiner wrote:
> ...
>> I'm not sure what you're getting at here. With the proposal Timon implemented we have the following:
>> - the newer, decoupled contract syntax that separates contract specification and implementation from each other; Timon's implementation uses asserts as the internal contract implementation AFAIK
>
> Not exactly. It actually _couples_ `in` expressions with assert expressions. In essence it just lowers
>
> int fun(int a)
> in(a)
> {
> }
>
> ...to:
>
> int fun(int a)
> in { assert(a); }
> {
> }
>
> This is a sensible default. In the future, some logic could be added to provide a hook to a different implementation of the `in` function, so that it would lower instead to:
>
> int fun(int a)
> in { __userDefinedInContract(a); }
> {
> }
>
> But I suspect the vast majority will stick with the default.

I think my proposal to add another use of semicolon in parentheses, like `foreach` or `for` but not the same as either, was needlessly complicated.

in (a)
out (result) (a)

as syntax sugar where each (a) lowers to
{assert(a);}
and in future can lower to something else, to renovate contract implementation

That's so much easier, in every way.
June 24, 2017
On Friday, 23 June 2017 at 21:36:07 UTC, Moritz Maxeiner wrote:
> Contracts within the DbC paradigm *are* abstractions that do not necessitate any particular implementation.

In practice, though, what must any such implementation actually achieve?

1. allow the source code to express its intent to the reader
2. prevent programs in invalid states from continuing
3. provide information about those invalid states after the fact

Goal 1 lies in the domain of the language grammar.
Goals 2 and 3 reflect the behind-the-scenes implementation of that grammar.

> Most native languages simply (sensibly) choose to use asserts for that.

Which could mean that they use the grammar of asserts, e.g. `assert(a, "message");`, or that they use a specific behind-the-scenes implementation of that grammar, i.e. the code that such a grammar compiles to.

> It would only couple the contracts with asserts if the DIP also specifies that asserts *must* be used for the lowering (which I would be against btw).

I think this reveals the sticking point. I think that the way D compiles assert expressions can and should be improved by making it more flexible behind the scenes. But that doesn't necessarily mean that the grammar needs to change. The problem is that we need to put *some* grammar into the new `in` expression design. If we allow, for example, a random sequence of function arguments, e.g.`in(a, b < 0, "yay!", myDvar)` there is no go-to way to implement it. The surface code would then require a particular backend implementation that could handle the grammar, and would furthermore now be coupled with that implementation. I'd rather not deal with that problem. It's vastly easier to just put my faith into the `assert` grammar, and hope that any improvements that it needs and receives will apply equally to `assert`s as well.
June 24, 2017
On 23.06.2017 21:04, H. S. Teoh via Digitalmars-d wrote:
> On Fri, Jun 23, 2017 at 06:57:57PM +0000, MysticZach via Digitalmars-d wrote:
>> On Friday, 23 June 2017 at 18:20:23 UTC, Moritz Maxeiner wrote:
>>> On Friday, 23 June 2017 at 18:03:26 UTC, Timon Gehr wrote:
> [...]
>>>> Agreed. Implementation:
>>>> https://github.com/dlang/dmd/compare/master...tgehr:contract-syntax
>>>>
>>>> (At most one contract of each type is supported. It is not very
>>>> hard to implement multiple contracts, but this requires touching
>>>> semantic analysis.)
>>>
>>> Holy ***. I set aside some time this weekend to try implementing
>>> this myself as an exercise, but oh well. Thanks!
>>
>> I know! I'd say it'll take me a good deal longer to rewrite the DIP
>> than he's taking to implement it!
> 
> Yeah!  Kudos to Timon for the quick implementation!

Thanks! :)

Support for multiple contracts:
https://github.com/dlang/dmd/compare/master...tgehr:contract-syntax

> This will increase
> the odds of this DIP being accepted, I'm sure. :-)
> 
> 
> T
> 
June 24, 2017
On Saturday, 24 June 2017 at 02:31:09 UTC, Solomon E wrote:
> I think my proposal to add another use of semicolon in parentheses, like `foreach` or `for` but not the same as either, was needlessly complicated.

It's very popular, actually. :)

> in (a)
> out (result) (a)

This resembles template function declarations. Both proposals resemble something else that they are not. Your proposal for `out` is attractive, actually, because the semantics of foreach are closer to what we're looking for than are the semantics of template declarations.

> as syntax sugar where each (a) lowers to
> {assert(a);}
> and in future can lower to something else, to renovate contract implementation

The foreach syntax can be just as easily lowered:

out(result; a)

...to:

out(result) {assert(a);}

That also includes the optional message.

out(result; result < 1, "alert!")

...lowers to:

out(result) { assert(result < 1, "alert!"); }

> That's so much easier, in every way.

There's no intention of making it complicated!