RacketContractsSafetyDesign-by-Contract

Contracts: Advanced Defensive Programming | Schema Programming Part 26

2.955 min read
Md Nasim SheikhMd Nasim Sheikh
Share:

Types tell you what data is (e.g., "an integer"). Contracts tell you how data should behave (e.g., "an integer greater than zero"). Racket has one of the most advanced contract systems in the world.

Advertisement

Basic Contracts

You use define/contract to attach a contract to a function.

#lang racket

(define/contract (deposit amount)
  (-> positive? any) ; Input must be positive, returns anything
  (printf "Depositing ~a\n" amount))

(deposit 100) ; OK
; (deposit -50) ; Contract Violation!

Higher-Order Contracts

Contracts can check functions passed as arguments.

(define/contract (apply-twice f x)
  (-> (-> number? number?) number? number?)
  (f (f x)))

This ensures f is a function that takes a number and returns a number.

Dependent Contracts

What if the output depends on the input?

(define/contract (increment x)
  (->i ([arg number?]) [result (arg) (> result arg)])
  (+ x 1))

This says: "The result must be greater than the argument".

Blame

The most important feature of contracts is Blame. If a contract is violated, Racket tells you exactly who broke it: the caller (for passing bad input) or the provider (for returning bad output).

Advertisement

Summary

Contracts allow you to enforce "business logic" rules that static types cannot catch. They are helpful for debugging large systems where it's hard to track down which module passed a null or a negative number.

Quick Quiz

If a function fails to return a value satisfying its output contract, who is blamed?

Md Nasim Sheikh
Written by

Md Nasim Sheikh

Software Developer at softexForge

Verified Author150+ Projects
Published:

You May Also Like