TL; DR; Основная причина - производительность. Вторая причина - это удобство использования.
Performace
Для переноса значения во время параметра (или тип result
) требуется выделение и стоимость его выполнения. По сути, если у вас была функция, возвращающая int
и поднимающая Not_found
, если ничего не было найдено, то при изменении этой функции на int option
будет выделено значение Some x
, которое создаст в штучной упаковке значение, занимающее два слова в вашей куче. , Это по сравнению с нулевым распределением в версии, которая использовала исключения. Наличие этого в узком цикле может резко снизить общую производительность. Как от 10 до 100 раз, правда.
Даже если возвращаемое значение уже упаковано, оно по-прежнему будет содержать дополнительное поле (одно слово служебной информации) и один уровень косвенности.
Юзабилити
В не тотальном мире скоро становится очень очевидным, что не тотальность заразна и распространяется по всему вашему коду. То есть, если в вашей функции есть операция деления, и у вас нет исключений, чтобы скрыть этот факт, то вы должны распространять не совокупность вперед. Вскоре у вас будут все функции с ('a,'b) result
, и вы будете использовать монаду Result
, чтобы сделать ваш код управляемым. Но Монада Результатов - не что иное, как ограничение исключений, только медленнее и более неловко. Поэтому мы вернулись к статус-кво.
Есть ли идеальное решение?
Видимо, да. Исключением является частный случай побочного эффекта вычислений. В настоящее время команда OCaml Multicore работает над добавлением системы эффектов в OCaml в стиле языка программирования Eff . Вот доклад , и я также нашел несколько слайдов . Идея состоит в том, что у вас могут быть преимущества двух миров - явная аннотация типа эффективной функции (как с вариантами) и эффективное представление с возможностью пропустить неинтересные эффекты (как с исключениями).
Что делать прямо сейчас?
Пока мы, обычные люди, ожидаем доставки эффектов в OCaml, нам все еще приходится жить с исключениями и вариантами. так что нам делать? Ниже приведен мой личный кодекс поведения, который я использую при программировании в OCaml.
Для решения проблемы юзабилити я использую правило - использовать исключения для ошибок и ошибок программиста. Более конкретно, если функция имеет проверяемое и четко определенное предварительное условие, то ее неправильное использование является ошибкой программиста. Если программа не работает, она не должна запускаться. Таким образом, используйте исключения, если предварительное условие не выполнено. Хорошим примером является функция Array.init
, которая завершается ошибкой, если аргумент size является отрицательным. Нет веских причин использовать тип суммы result
, чтобы сообщить пользователю функции, что она использовала его неправильно. Критическим моментом с этим правилом является то, что предварительное условие должно быть проверяемым, а это означает, что проверка является быстрой и легкой. То есть, хост существует или сеть достижима не является предварительным условием.
Чтобы решить проблему с производительностью, я пытаюсь предоставить два интерфейса для каждой неполной функции: один, который явно вызывается (это должно быть указано в имени), а другой использует тип результата в качестве возвращаемого значения. С последним осуществляется через первый.
Например, что-то вроде find_value_or_fail
или (при использовании стиля Janesteet find_exn
и просто find
.
Кроме того, я всегда стараюсь сделать свои функции надежными, в основном следуя принципу надежности интернета. Или, с логической точки зрения, сделать их более сильными теориями. Другими словами, это означает, что я пытаюсь минимизировать набор предварительных условий и обеспечить разумное поведение для всех возможных входных данных. Например, вы можете обнаружить, что резкое деление на ноль имеет четко определенное значение в модульной арифметике, при котором GCD и LCM начнут иметь смысл, когда решетка делимости соответствует и присоединиться к операциям.
Наш мир, вероятно, является более полным и полным, чем наши теории, поскольку мы обычно не видим вокруг себя множества исключений :) Поэтому, прежде чем вызывать исключение или указывать на ошибку каким-либо иным способом, подумайте дважды, является ли она ошибкой илиэто просто неполнота вашей теории.