Here is my thinking on the DbC feature ...
Implement the full semantics of Eiffel DbC and improve upon it.
Don’t use annotations - Ughhh. Many contract frameworks tack it on and the expressions are all enclosed in a string which prevents syntax highlighting, refactoring, type checking etc DdC needs to be built into the language itself and so IDEA can work with it in the AST.
Don’t forget “check” assertions - they are also useful in addition to require, ensure and invariant.
I was thinking along the lines of :
{code}
require
there must be at least one product : products.size > 0
the product index must be within the valid range : index > 0 && index <= products.length,
“The index {index} is not within the range 0 to {products.length}”
{code}
(This is very close to how I implemented a simple DbC framework in groovy many years ago)
This is not exactly following Eiffel, I have made the following improvements:
-
Mandatory labels
These are important as its good to have a human readable version of the assertion because:
a) It aids the USER of a framework in understanding how to use it.
b) It helps diagnose bugs when the label is added to a contract violaton exception then logged or alerted to the developer. -
Contract violation messages
Added into the exception, these give more details about the offending values to help track bugs faster. -
Ordering is significant
The second requirement is dependent on the first. i.e. if the first is violated the second is not relevent. This saves duplicating the first assertion in the second just to avoid multiple violations. -
Allow some variable initialisation code prior to requirement assertion in a method.
On the topic of multiple violations perhaps there is an opportunity here to allow multiple violations and define the dependencies e.g.:
{code}
init
val languages = allProducts.filter {it.category == language}
val MAX_PRICE = 1000
require
there must be at least one language product : languages.size > 0
{
the product index must be within the valid range : index > 0 && index <= products.length,
“The index {index} is not within the range 0 to {products.length}”
all languages must be cheap: languages.forall {it.price < MAX_PRICE},
“These languages are not cheap: {languages.filter {it.price >= MAX_PRICE}}”
}
{code}
In the case above the last two requirements could both be violated giving the developer more information up front.
This means adding more than one contract violation to a single exception - perhaps this is too complex.