I'm writing a DbC (Design by Contract) library for Nim and I would like you to 
give me your thoughts on this topic (references at the end).

I wanted to get into Nim's code transformations so I thought it would be a good 
idea to try implementing some simple libraries. Actually, this one was ready in 
the present form more than two months ago but I didn't feel like publishing it 
yet as it lacked crucial (or so I thought) features like, let's say, 
inheritance. Due to lack of time (and being lazy).

# Compiler extensions / module-range macros

As far as I know, Nim deserves a name of "extremely statically compiled 
language", one of the reasons being advanced compile-time checks (like 
overloading for _static_ arguments or _noSideEffect_ pragma). It sounds 
reasonable to extend it with a prover. I thought it would be nice to use it 
just like any other nimble package. Unluckily just importing a package can't 
(as far as I know) enable any code transformation for the module (unlike Rust 
plugins) but wrapping the code doesn't sound all that bad. Maybe anyone here 
have better ideas for making an easy-to-install compiler extension?

# Exceptions

I'm not sure if exception-aware contracts would be a good thing to do. Of 
course they would complicate proving process but if any exception possible to 
throw would need to be included in contract signature so that the prover knows 
what conditions are fulfilled if the exception is raised (or even why it could 
be thrown), it could probably help using formal contracts in error-prone 
environments.

Why even bother? There are cases when we can't guarantee that the operation 
will be finished successfully but we can, let's say, promise that even if it 
doesn't, it won't corrupt it's arguments. Like impossible swap will just leave 
it's arguments as they are.

# Type invariant inheritance

I have seen at least three approaches to type invariant (single) inheritance 
none of which sounds perfect. Some reasonable contracts are difficult to write 
down using variable-oriented type invariants but using quantifiers, while 
handy, is troublesome in implementation if it's bound not to be ridiculously 
inefficient.

It seems to me that UML-like contracts could be a good idea but... they only 
handle very specific traits (e.g. _add-only_, _unique_, _sorted-by_). It could 
be also nice to introduce analogical traits for subroutines, e.g. _commutative_ 
or _associativeWith_. Maybe custom contractual traits declarations would do?

What grammar should contractual type invariants (or type traits) use? Nim's 
grammar seems a bit limited here (especially lack of macro-pragma for fields) 
and macros have to accept parsable Nim. I considered a few possibilities:

  * mock field – objects-only; as the contract's body is parsed as the field's 
type, no more than one expression is accepted


    
    
    type parityPair = object of RootObj
      a: int
      b: int
      invariant:
        a + b mod 2 == 0

  * invariant subroutine – less compact, doesn't seem like a part of the 
language; using the type before declaring invariant possible


    
    
    invariant(p: parityPair) =
      p.a + p.b mod 2 == 0
      anotherRule(p.a, p.b)

  * new type declaration block – seems less natural


    
    
    typeWithInvariant parityPair of RootObj:
      a: int
      b: int
      invariant:
        a+b mod 2 == 0
        anotherRule(a, b)
    

Of course there are other details like how to express 'previous iteration' 
concept gracefully and many more.

Glad for any help.

Basics: 
[https://en.wikipedia.org/wiki/Design_by_contract](https://en.wikipedia.org/wiki/Design_by_contract)

My library on github: 
[https://github.com/Udiknedormin/NimContracts](https://github.com/Udiknedormin/NimContracts)

Reply via email to