How do I use in contract with interface?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Wed Nov 15 15:14:04 UTC 2017


On Wednesday, November 15, 2017 14:43:33 Dr. Assembly via Digitalmars-d-
learn wrote:
> I'm learning to use interface with contracts. In below code, in
> isn't being "called". Can someone point out why? what am I doing
> wrong?
>
> void main() {
>   C c = new C();
>   writeln(c.foo(1));
> }
>
> interface I
> {
>   int foo(int i)
>       in { assert(i > 2); }
>       out (result) { assert(result != 0); }
>
>   void baa();
> }
>
> class C : I
> {
>   int foo(int i) {
>       return i * 2;
>   }
>
>   void baa() {
>       writeln("Hello!");
>   }
> }

Okay. When inheritance gets involved, contracts get a bit special. If you
had a free function or a struct's member function, things would be simple
enough. The in contract would be run before the function's bode was run, and
the out contract would be run afterwards. If either failed, an AssertError
would be thrown. However, it works a bit differently with classes. To quote
the documentation ( section 23.3: https://dlang.org/spec/contracts.html ):

===========
1. If a function in a derived class overrides a function in its super class,
then only one of the in contracts of the function and its base functions
must be satisfied. Overriding functions then becomes a process of loosening
the in contracts.

2. A function without an in contract means that any values of the function
parameters are allowed. This implies that if any function in an inheritance
hierarchy has no in contract, then in contracts on functions overriding it
have no useful effect.

3. Conversely, all of the out contracts need to be satisfied, so overriding
functions becomes a processes of tightening the out contracts.
===========

So, effectively, in contracts are all ||ed and out contracts are all &&ed,
and the lack of an in contract means that that contract passes. So, if you
don't have an in contract, or if you have an empty one, then all base class
(or interface) contracts are pointless for that derived function. So, in
contracts only really get inherited in the sense that it gives you another
contract that could pass. It really doesn't provide a way to restrict
derived functions. So, it's pointless to put an in contract on an
interface's function unless you're trying to ensure that nothing in derived
contracts is any stricter than that contract, which in practice likely means
that it's pointless to put an in contract on an interface function.

However, out contracts do restrict derived functions, since those are
effectively &&ed together. So, it can make sense to put those are
interfaces.

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list