Дизайн по контракту в Swift

Предоставляет ли Swift официальную поддержку Design by Contract? Я понимаю, что это можно сделать во время выполнения через утверждения, но может ли это быть сделано во время компиляции? Или есть ли какие-либо внешние плагины/библиотеки, которые это делают?

ИЗМЕНИТЬ

Говоря "во время компиляции Design by Contract", я не хочу, чтобы библиотека была всем мощным статическим анализатором, который имеет С#. Мне было бы достаточно, если бы это было похоже на то, что iContract предоставляет Java. Давайте посмотрим на пример:

Код DBC для оценки квадратного корня в Java с использованием iContract может быть записан как:

/** 
 * @pre f >= 0.0
 * @post Math.abs((return * return) - f) < 0.001 
 */ 
public float sqrt(float f) { ... } 

Теперь это сохраняет мой контракт как часть спецификации API, а не часть его реализации, которая, по моему мнению, является более чистым способом. Вызывающий должен знать, каковы его обязанности, а вызывающий настраивает свое ожидание, хотя и более четко. У нас есть что-то подобное в Swift?

Ответы

Ответ 1

TL; DR

Как отмечает @Tommy в комментариях по вашему вопросу, кажется, что простой и простой ответ на ваш вопрос: "Нет, время компиляции DbC в настоящее время не является функцией Swift".


Что теперь построено?

Для встроенной поддержки такого типа стратегии разработки вы должны смотреть на время выполнения, я боюсь. Кажется, что Swift предпочитает утверждения во время исполнения для обеспечения предварительных условий в настоящее время, хотя в общем случае язык обычно уделяет больше внимания безопасности во время компиляции (подробнее об этом ниже). Глобальные функции assert, assertionFailure, precondition и preconditionFailure предназначены для широкого распространения по всему коду без влияния на производительность сборки релиза.

Модульные тесты - это, конечно же, еще одна стратегия для проверки того, что контракты API выполняются, но их нужно учитывать и реализовывать вручную, а также подвержены ошибкам.

Что-то еще, что, возможно, интересно отметить, заключается в том, что среди лучшей поддержки комментариев документации Swift 2 "требуется", "предварительное условие" и "постусловие" распознаются ключевые слова разметки, так что они отображаются в быстрой справочной документации:

/// - precondition: f >= 0.0
/// - postcondition: abs((return * return) - f) < 0.001
/// - returns: The square root of `f`.
func sqrt(f: Float) -> Float { ... }

Таким образом, этот акцент на том, чтобы быть в состоянии обеспечить хорошую документацию для контрактов API, означает, что команда разработчиков Swift явно заботится об этом, и это промежуточный пробел, пока они не включат что-то в синтаксис в будущем, или это означает что они считают, что такая информация принадлежит документации? Возможно, бессмысленная постуляция. Несмотря на это, несмотря на то, что он не является надлежащим DbC, я думаю, что это удобная вещь, о которой нужно знать прямо сейчас.


Что я могу сделать с этим сейчас?

С макросами Objective-C, можно использовать, чтобы существенно реализовать базовый DbC, однако нехватка макросов в Swift означает, что вам придется прибегать к какой-то функции /generics -based wrapper, который, как я думаю, будет выглядеть действительно неудобно.

Поддержка Xcode для добавления пользовательских сценариев к фазам целевой сборки - как это предлагает @JonShier в комментариях, - возможно, самая близкая вы получите к полезным и автоматическим DbC, не дожидаясь, пока язык (возможно, может быть, нет) представит такие особенность. С вышеупомянутыми ключевыми словами разметки документации script, который анализирует комментарии к документации для сборки модульных тестов, может быть даже ретроспективно включен в проекты с небольшим количеством обучения/усилий со стороны пользователя. Как вы говорите, я думаю, что это может сделать очень интересный проект!


Будет ли это встроенная функция в будущем?

Неясно, может ли встроенный DbC быть включен в Swift в будущем. Вероятно, это функция, которая хорошо подходит для миссии языка Swift, то есть она способствует более безопасному коду и снижает риск ошибок времени выполнения. Если он станет частью языка, я бы предположил, что мы с большей вероятностью увидим, что они отображаются как атрибуты объявлений, чем как интерпретированная разметка комментариев, например:

@contract(
    precondition = f >= 0.0,
    postcondition = abs((return * return) - f) < 0.001
)
func sqrt(f: Float) -> Float { ... } 

(Но это только предположение и бесполезно для нас прямо сейчас!)

Из того, что я знаю о теме, время компиляции DbC может быть очень сложной задачей. Но кто знает... работа над Clang Static Analyzer, безусловно, показала, что есть основное желание перетащить идентификацию ошибок времени выполнения во время компиляции. Возможно, это идеальная проблема для того, чтобы статический анализатор Swift работал в будущем?

Ответ 2

Я не, если это то, что вы ищете, но вот предложение, которое вы могли бы попробовать, возможно. Если вы хотите определить протокол, в котором вы можете определить подпись функции sqrt и оставить реализацию для других классов или структур, которые будут реализованы позже, вы можете сделать что-то вроде кода ниже:

Примечание: sqrtf просто использует здесь реализацию системы.

public protocol Math {
    func sqrtf(f: Float) -> Float
}

struct NativeMath: Math {
    func sqrtf(f: Float) -> Float {
        return sqrt(f)
    }
}


println(NativeMath().sqrtf(2))