# Design by Contract
DWScript supports Design by Contract (DbC) natively, allowing you to define preconditions and postconditions for your subroutines. This helps ensure code correctness and robust error handling.
## Preconditions (require)
Use `require` to specify conditions that must be true *before* the subroutine executes. If a condition fails, an `EAssertionFailed` exception is raised.
You can provide a custom error message using the `:` syntax.
```pascal
function Divide(a, b : Integer) : Float;
require
b <> 0 : 'Denominator must not be zero';
begin
Result := a / b;
end;
```
## Postconditions (ensure)
Use `ensure` to specify conditions that must be true *after* the subroutine executes. You can access the result using `Result` and the original value of parameters using the `old` keyword.
```pascal
procedure Deposit(var balance : Float; amount : Float);
require
amount > 0;
begin
balance += amount;
ensure
balance = old balance + amount;
end;
```
:::info
The `old` keyword captures the value of the expression at the moment the subroutine was entered.
:::
## Contract Failures
When a contract is violated, the script engine raises an `EAssertionFailed` exception. This allows you to catch and handle contract violations during development or in specific error-handling blocks.
```pascal
function Divide(a, b : Integer) : Float;
require
b <> 0 : 'Denominator must not be zero';
begin
Result := a / b;
end;
try
Divide(10, 0);
except
on E: EAssertionFailed do
PrintLn('Contract failed: ' + E.Message);
end;
// OUTPUT
// Contract failed: *Denominator must not be zero
```
## Contracts & Inheritance
Contracts are inherited and follows the "Liskov Substitution Principle":
* **require**: A subclass can only *weaken* preconditions (i.e., accept more inputs). In practice, this means `require` in an overridden method is ORed with the base class requirement.
* **ensure**: A subclass can only *strengthen* postconditions (i.e., guarantee more outcomes). In practice, this means `ensure` in an overridden method is ANDed with the base class guarantee.
## Production Builds
Contracts are powerful for development and debugging, but they do incur a small performance overhead. In high-performance production environments, contract checking can be disabled via compiler options, effectively turning them into no-ops.
:::info
#### Summary
Design by Contract is a philosophy of "Fail Fast". By explicitly stating assumptions, you make your code self-documenting and much easier to debug.
:::
Design by Contract
DWScript supports Design by Contract (DbC) natively, allowing you to define preconditions and postconditions for your subroutines. This helps ensure code correctness and robust error handling.
Preconditions (require)
Use require to specify conditions that must be true before the subroutine executes. If a condition fails, an EAssertionFailed exception is raised.
You can provide a custom error message using the : syntax.
function Divide(a, b :Integer):Float;require
b <>0:'Denominator must not be zero';begin
Result := a / b;end;
Postconditions (ensure)
Use ensure to specify conditions that must be true after the subroutine executes. You can access the result using Result and the original value of parameters using the old keyword.
The old keyword captures the value of the expression at the moment the subroutine was entered.
Contract Failures
When a contract is violated, the script engine raises an EAssertionFailed exception. This allows you to catch and handle contract violations during development or in specific error-handling blocks.
function Divide(a, b :Integer):Float;require
b <>0:'Denominator must not be zero';begin
Result := a / b;end;try
Divide(10,0);excepton E: EAssertionFailed do
PrintLn('Contract failed: '+ E.Message);end;
Result
Contract failed: *Denominator must not be zero
Contracts & Inheritance
Contracts are inherited and follows the "Liskov Substitution Principle":
require: A subclass can only weaken preconditions (i.e., accept more inputs). In practice, this means require in an overridden method is ORed with the base class requirement.
ensure: A subclass can only strengthen postconditions (i.e., guarantee more outcomes). In practice, this means ensure in an overridden method is ANDed with the base class guarantee.
Production Builds
Contracts are powerful for development and debugging, but they do incur a small performance overhead. In high-performance production environments, contract checking can be disabled via compiler options, effectively turning them into no-ops.
Summary
Design by Contract is a philosophy of "Fail Fast". By explicitly stating assumptions, you make your code self-documenting and much easier to debug.