On 6/20/17 1:42 PM, H. S. Teoh via Digitalmars-d wrote:
On Tue, Jun 20, 2017 at 11:57:55AM +0000, Mike Parker via Digitalmars-d wrote:
DIP 1009 is titled "Improve Contract Usability".

https://github.com/dlang/DIPs/blob/master/DIPs/DIP1009.md
[...]

What would a body-less declaration of a function look like under the new
syntax? Hopefully not this:

        int myFunc(Args...)(Args args)
        if (Args.length > 2)
        in assert(args[0] != 0);        // semicolon: ouch
        in assert(args[1] > 1);              // semicolon: ouch
        // How do we end the declaration here? Another semicolon?
        ;       // ouch

Having several semicolons outside a braced block makes declarations
harder to parse. External tools will no longer be able to just scan for
top-level semicolons to find the end of the declaration, but will have
to understand contract syntax too, even if that particular tool doesn't
care about contracts.

It gets worse if your contract involves calling another function; you'll
end up with:

        int myFunc(Args...)(Args args)
        if (Args.length > 2)
        in assert(args[0] != 0); // is this the end of the declaration?
        in otherFunc(args[0]);  // is this declaring another function?
                                // (i.e., a typo of int -> in?)
        ;       // ouch

Also, I don't like the idea of putting contracts inside the function
body. As the DIP already mentions, this makes parsing of contracts more
difficult. It also causes cognitive dissonance (contracts are a part of
the function's signature, not its implementation).

It's even worse if you allow contracts in arbitrary places inside the
function body -- then even somebody reading the code wouldn't know, at a
glance, what the contracts are, without scanning the entire function
body! That makes contracts *harder* to read and use, rather than easier,
in direct contradiction of the purpose of this DIP.


Here's my counter-proposal: since the sig constraint line uses
parentheses (and yes, I deliberately planted a sig constraint above just
to make this point), why not go for syntactical symmetry? I.e., like
this:

        int myFunc(Args...)(Args args)
        if (Args.length > 2)
        in (args[0] != 0)
        in (args[1] > 1);    // one semicolon to end them all

This is much much better. The verbosity of contracts isn't really the brace, it's the asserts. This also gives the compiler a better handle on what causes the thing to fail (better error message).

Note that you NEED the semicolon for the DIP's proposal, because `in` is also a binary operator, and could be misinterpreted. With yours, it's not possible to misinterpret.

For out-contracts, we could use the existing lambda syntax to avoid the
ugliness of having two parenthesized expressions next to each other:

        // Body-less declaration
        int myFunc(Args...)(Args args)
        if (Args.length > 1)
        in (args[0] > 0)
        out (result => result > 10);
        // N.B.: instead of: `out(result)(result > 10)` which is uglier.

        // Full declaration
        int myFunc(Args...)(Args args)
        if (Args.length > 1)
        in (args[0] > 0)
        out (result => result > 10)
        {
                ... // function body goes here
        }

I'm not understanding that last part. Current syntax would be:

out(result)
{
   // check result
}

I'm concerned this would be ambiguous with the current syntax.

IMO, this whole proposal doesn't carry enough weight, either your version or the DIP itself. I would not be in favor. Current syntax is understandable, and not too verbose IMO.

-Steve

Reply via email to