Проектирование по контракту в Swift

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

редактировать

говоря "во время разработки времени компиляции по контракту", я не имею в виду, что библиотека будет все мощный статический анализатор, который C# имеет. Мне было бы достаточно, если бы это было что-то вроде одного этот iContract обеспечивает Java. Давайте рассмотрим пример:

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

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

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

2 ответов


TL; DR

как указывает @Tommy в комментариях под вашим вопросом, казалось бы, что простой и простой ответ на ваш вопрос: "нет, время компиляции DbC в настоящее время не является функцией Swift".


что встроено прямо сейчас?

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

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

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

/// - 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 означает, что у вас будет прибегнуть к какой-то функции / обертке на основе дженериков, которая, я думаю, будет выглядеть очень неудобно.

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


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

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

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

(но это только предположения, и они нам сейчас не нужны!)

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


Я не, если это то, что вы ищете, но вот предложение, которое вы могли бы попробовать. Если вы хотите определить протокол, где вы можете определить подпись функции 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))