an old topic (pun intended)

Davidson Corry davidsoncorry at comcast.net
Sat Oct 29 20:21:11 PDT 2011


On 10/28/2011 5:10 AM, kennytm wrote:
> Davidson Corry<davidsoncorry at comcast.net>  wrote:
>> >  ...it occurred to me the other day that we could write contracts as
>> >
>> >       void foo(T t)
>> >       {
>> >           scope(in) {
>> >                // pre-condition contracts
>> >           }
>> >           scope(out) {
>> >                // post-condition contracts
>> >           }
>> >           // ...body of function...
>> >       }
>> >
>> >  and eliminate the 'in', 'out' and 'body' keywords/constructs entirely.

Just in passing, I think that 'scope(requires)' and 'scope(ensures)' are 
somewhat more evocative of what these blocks actually do than 
'scope(in)' and 'scope(out)' would be. The words 'in' and 'out' have so 
many other connotations that they could be confusing.

>> >  Similarly, an invariant could appear in the default constructor of a class as
>> >
>> >       this()
>> >       {
>> >           scope(invariant) {
>> >               // invariant guarantees...
>> >           }
>> >           // ...body of constructor...
>> >       }
>> >
>> >  Or*any*  constructor, really, although you would probably want the
>> >  compiler to enforce that no more than one constructor defined a
>> >  scope(invariant) block. This notation also suggests (correctly) that the
>> >  invariant doesn't take effect until you have entered the constructor.
>> >  (Exited it, really, but...)
>
> The contracts are parts of the function's interface, not implementation. If
> you put the scope(in/out) inside the '{ ... }' how would a .di file handle
> it?
>
> And class invariant is also checked outside the constructor. Your syntax
> makes it look like it will run only when the constructor is called.

Good point. A class invariant is special enough that it should be 
declared at class scope, rather than inside any particular method
(including constructors):

     class foo {
         scope(invariant) { /* the invariant checks */ }
         // implementation of the class...
     }

As for .di files, those can declare the contracts inside the braces and 
simply elide the body of the function. This is similar to Eiffel's 
short-flat form. Eiffel doesn't use braces for statement grouping or 
lexical scoping, but its contracts are just as much "inside" the 
function or method or class as the parameter lists of those functions or 
methods are.

Positioning the contract blocks inside the braces is also suggestive of 
the lexical environment (the "scope", although I'm trying not to use 
that word because it's overloaded in this context) within which the 
contract testing code runs -- anything that could be declared or 
referenced at that position in the source code is available to the 
contract code. (As with 'static if', the braces around a contract block 
are for grouping, and do *not* introduce a new lexical scope. You would 
need to {{double-brace}} the block to introduce new lexical scope, as 
you do with 'static if'.)

    ============

I do think that using the 'scope(something)' form for contracts is still 
a good idea.

'scope' is one of the big wins of the D design team. It allows the 
programmer to declare code over *here* where it's close to the resource 
it's going to clean up after, while making that code effective over 
*there* where the clean-up needs to be done -- upon exit from a block, 
upon failure of a block, etc. Or in this proposal, upon entry/exit to a 
class method (invariant) or upon entry into (requires) or exit from 
(ensures) a class method or a bare function... all without requiring the 
user to keep track of a complex scaffolding of try/catch/finally blocks, 
which the compiler manages for you.

It has a bit of the flavor of aspect-oriented programming, but without 
AOP's vagueness about what's going to happen when and where.

-- Davidson



More information about the Digitalmars-d mailing list