On 15/04/2019 09:41, Sven Barth via fpc-pascal wrote:
Am 14.04.2019 um 23:48 schrieb Martin Frb:
type
TFoo= class
function DoTheFooThing(Foo1, Foo2: TFoo): Tbar;
requires
assigned(Foo1) or assigned(Foo2): 'Need at least 1 foo,
for the connection';
guarantees // better than ensure
assigned(result);
result.KnowsMyFoo = true: 'Connection exists'; // the
=true is redundant
procedure DoTheBar;
end;
It is to be noted, that requires and guarantees contain conditions
(expressions), not pascal code. So technically it is ok, that they
are in the interface and not implementation.
If I want something in the implementation, I can use normal "assert"
(which by the way, have often great documenting value)
The problem is that both "require" and "ensure" can check for fields
as well (think of a setter for example or something that changes the
state). Thus you could use a field name that the compiler does not yet
know. So you would need to order your methods in a order dictated by
the compiler due to the method's implementation instead of an order of
your own choosing.
And yes, that would also be a problem with "class invariants", though
there it's more clear if we say that only identifiers can be used that
have been declared before as it's the same with properties and their
setters/getters.
Also to be ask if properties can have contract conditions. Especially
thinking of indexed properties, where the index is a constant. Several
properties using the same getter/setter (with diff index) may have
different conditions for the contract.
Yes accessing fields is valid. Though easily leads to confusion what
should and what should not be in the contract. (Yet that is not to be
enforced...)
I saw an example, where the "ensure" of a setter checked that the field
was set. That may be valid, but it also may have been something for a
normal assert. Depends on the intend.
The ensure (again I prefer guarantees) is a contract. (between the
class/method and someone else).
So if the check for the field is an internal detail, it should be a
normal assert. (the getter result, could be part of the contract then /
that is different)
Only a normal assert is not quite the same. Contracts are checked too,
if an inherited overwritten method is called. Assert are not (not if
there is no call to inherited).
So a contract post condition could be used to make sure that any
overwritten setter method will have changed the field. In that case the
partner in the contract is the inherited class. And the post condition
is less of a guarantee, but more a hidden requirement to the contract
partner.
Anyway about the field order.... (and there could be circular
requires/guarantees)
It would be an option to specify the contract details deferred
type
TFoo= class
function DoTheFooThing(Foo1, Foo2: TFoo): Tbar;
procedure DoTheBar;
// need full declaration, could be overloaded // may skip param names?,
just types should be ok
requirements for DoTheFooThing(Foo1, Foo2: TFoo): Tbar;
assigned(Foo1) or assigned(Foo2): 'Need at least 1 foo, for
the connection';
guarantees for DoTheFooThing(TFoo, TFoo): Tbar;
assigned(result);
result.KnowsMyFoo = true: 'Connection exists'; // the =true
is redundant
end;
Bit awkward because you need the full signature....
The compiler could allow both the "requires" right after the method, and
the deferred "requirement for"
Alternative (but I do like that even less) named forward requirements
type
TFoo= class
function DoTheFooThing(Foo1, Foo2: TFoo): Tbar; requires
'WhatTheFooWants';
procedure DoTheBar;
requirements for WhatTheFooWants;
assigned(Foo1) or assigned(Foo2): 'Need at least 1 foo, for
the connection';
end;
That way, 2 methods could refer to the same requirements block.
Then it could even be possible to refer to several blocks....
function DoTheFooThing(Foo1, Foo2: TFoo): Tbar; requires
'WhatTheFooWants', 'TheFooSpecials';
But this will make it hard to read. Especially in the reverse, if you
are in a named requirement block, it is not easy to find all methods
that are affected by it.
Anyway just throwing in some ideas and possibilities.
_______________________________________________
fpc-pascal maillist - fpc-pascal@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal