Я думаю, вы спрашиваете, как система контрактов может работать без ООП и наследования? Как пользователь Racket, который не знаком с Eiffel, я удивляюсь, почему система контрактов имеет какое-либо отношение к ООП и наследованию. :)
На практике я считаю контракты Racket способом получения некоторых преимуществ статических объявлений типов, сохраняя при этом гибкость динамически типизированных языков. Плюс контракты выходят за рамки просто типов и могут выполнять роль утверждений.
Например, я могу сказать, что функция требует один аргумент, который является точным целым числом ... но также сказать, что это должно быть точное положительное целое число, или объединение определенных конкретных значений, или фактически любой произвольно сложный тест пройденного значения. Таким образом, контракты в Racket сочетают в себе то, что вы могли бы сделать с (a) объявлениями типа и (b) утверждениями, скажем, C / C ++.
Одна проблема с контрактами в Racket - это то, что они могут быть медленными. Один из способов справиться с этим - сначала использовать их при разработке, а затем выборочно удалять их, особенно из типов функций «внутреннего цикла». Другой подход, который я пробовал, заключается в том, чтобы включить или выключить их оптом: создайте пару модулей, таких как contract-on.rkt и contract-off.rkt, где последний предоставляет некоторые макросы, которые ничего не делают. Ваши модули требуют контрактов.rkt, который предоставляет все из файлов -on или -off. Это похоже на компиляцию в режиме DEBUG vs RELEASE.
Если вы приехали из Eiffel, возможно, мой уклон на C / C ++ для контрактов на Racket не поможет, но я все равно хотел поделиться им.