Илья Ермаков писал(а):
Тут же к вопросу об обработке исключений - мне кажется, что конструкции try-except (в полезности которых многие давно сомневались) совершенно бесполезны в параллельных приложениях. Т.к. искать обработчик исключительной ситуации раскруткой стека текущего потока бессмысленно, этот поток не может и не должен ничего знать об обработке исключений (а если всё-таки должен, то достаточно обычных кодов ошибок).
Обработчики исключений должны быть обычными callback-объектами, с соотв. конкретным возможным проблемам интерфейсами. Приложение описывает эти обработчики и регистрирует их в соотв. службе. Т.е. никаких спец. языковых механизмов, только обычные ОО-паттерны.
Я тут подумал -- а зачем ещё и паттерны ООП привлекать-то? :о))
Вот возьмём (ну конечно же) тот же Хаскелл. В нём нет специальной языковой конструкции тип try-except, есть просто несколько стандартных функций: catch, try, bracket, finally для обработки исключений и ioError -- для их генерации...
Простейший пример:
Код:
main = do
print $ 1 `div` 0
Как и следовало ожидать, при выполнении образуется исключение: divide by zero. Как его перехватить? Ну, например, вот так:
Код:
import Control.Exception as CE
main = do
print $ 1 `div` 0
`CE.catch` \err -> print $ "Oops! Something wrong: " ++ show err
А если надо просто попытаться выполнить какой-то код, игнорируя возможные ошибки, то можно сделать так:
Код:
import Control.Exception
main = do
try $ print $ 1 `div` 0
Функции try и finally являются аналогом оператора try-finally в Дельфях. Позволяют делать так:
Код:
import Control.Exception
main =
try $ do
open_resources -- открываем какие-нибудь файлы или прочие ресурсы
do_something -- делаем что-то, что может привести к исключению
`finally`
close_resources -- закрываем открытые ресурсы
Или более продвинуто -- с обработкой возникших неприятностей:
Код:
import Prelude hiding (catch)
import Control.Exception
main =
do
open_resources -- открываем какие-нибудь файлы или прочие ресурсы
do_something -- делаем что-то, что может привести к исключению
`finally`
close_resources -- закрываем открытые ресурсы
`catch` \err -> case err of -- Обрабатываем возникшие исключения
ArithException DivideByZero -> print "Oops! Division by Zero"
Deadlock -> print "Oops! All threads are blocked"
others -> print $ "Oops! " ++ show others
Функция bracket чем-то похожа на оператор using из C#. Можно делать, например, так:
Код:
main = do
bracket
(openFile "filename" ReadMode) -- открываем файл
(hClose) -- закрываем его, что бы ни случилось
(\handle -> do { ... }) -- если открылся нормально, работаем с ним
Любимый лисперами макрос with-file будет выглядеть так:
Код:
withFile name mode = bracket (openFile name mode) hClose
и все дела! Вот она, сила функционального программирования! :о) Новая продвинутая (для каких-нить там джавистов или сишарперов) языковая конструкция задаром, просто в виде функции!
С одной стороны, такой набор гибких функций, а не жёстких операторов, может выглядеть моментами как привносящий некоторый синтаксический оверхед (типа `catch` \err -> case err of), что не очень приятно, но вполне терпимо.
С другой стороны, это позволяет при необходимости вносить в логику обработки исключений свои собственные поправки/изменения/дополнения, не затрагивая компилятор или стандартные библиотеки...
Например, Булат Зиганьшин в своём архиваторе FreeArk легко сделал такие поправки, что бы перехватывать нажатие на Ctrl-C и корректно закрывать все файлы и прочие дела при этом...
ЗЫ. А вот интересно, как будет выглядеть использование подобных процедур в таких языках (с библиотечной поддержкой исключений), как тот же Оберон? ;о) Небось, нечто жуткое и невообразимое? :о))