F # конструкции обработки исключений - PullRequest
8 голосов
/ 16 января 2010

Почему F # не поддерживает блок try / with / finally?

Разве не имеет смысла пытаться что-то, иметь дело с любым исключением, которое он выдает, хотя бы для регистрации исключения, а затем убедитесь, что какой код выполняется после всего этого?

Конечно, мы можем сделать

try
    try
        ...
    with ex -> ...
finally
    ...

Но это кажется слишком искусственным, оно ясно демонстрирует, что «F # против try / with / finally». Почему это?

Ответы [ 5 ]

12 голосов
/ 17 января 2010

Как уже упоминалось, вы обычно используете try-with-finally, чтобы убедиться, что вы правильно освободили все ресурсы в случае исключения. Я думаю, что в большинстве случаев вы можете сделать это проще, используя ключевое слово use:

let input = 
  try
    use stream = new FileStream("C:\temp\test.txt");
    use rdr = new StreamReader(stream);
    Some(rdr.ReadToEnd())
  with :? IOException as e -> 
    logError(e)
    None

Я думаю, что это в основном причина, по которой вам не нужно try-with-finally так часто, как в других языках. Но, конечно, в некоторых ситуациях это может понадобиться (но, конечно, этого можно избежать, создав экземпляр IDisposable с использованием выражений объектов (что синтаксически очень просто). настолько редко, что команде F # на самом деле не нужно беспокоиться об этом.

6 голосов
/ 17 января 2010

ортогональность?Вы можете просто вложить «попробуй с» в «попробуй наконец», как ты покажешь.(В любом случае, это то, что происходит на уровне IL).

Тем не менее, попытка с окончанием - это то, что мы можем рассмотреть в будущей версии языка.

ЛичноЯ столкнулся с желанием всего лишь пару раз, но когда вам это нужно, немного скучно делать дополнительный вложение / отступ.В общем, я нахожу, что я редко пишу код обработки исключений, и это обычно просто один или другой (например, наконец, чтобы восстановить инвариантную или другую транзакционную семантику, или 'catch' в верхней части приложения, чтобы записать исключение или показатьпользовательская диагностика).

Но я не думаю, что здесь есть что почитать о дизайне языка.

2 голосов
/ 10 мая 2012

Не вдаваясь в детали, потому что детали - в

Эксперт .NET 2.0 IL Ассемблер Серж Лидин

См .: гл. 14, управляемая обработка исключений

"Обработчики finally и fault не могут мирно сосуществовать с другими обработчиками, поэтому если защищенный блок имеет ошибку finally или обработчик, у него не может быть ничего другого. Чтобы объединить обработчик finally или fault с другими обработчиками, вам нужно вложить защищенные блоки и блоки обработчика в другие защищенные блоки, ..., так что каждый обработчик finally или fault имеет свой собственный защищенный блок. "

стр. 300

В методе try / catch используется обработчик fault , а в методе try / finally используется обработчик finally .

См .: Метод ILGenerator.BeginFaultBlock

Если вы генерируете обработчик fault в блоке исключений, который также содержит обработчик catch или обработчик finally , полученный код непроверяемый .

Итак, можно считать, что все языки .net используют синтаксический surgar, и, поскольку F # настолько нов, они просто еще не реализовали его. Без вреда, без суеты.

1 голос
/ 16 января 2010

Я уточню свой комментарий в этом ответе.

  1. Я утверждаю, что нет причин предполагать, что вы хотите перехватывать исключения и завершать некоторые ресурсы на том же уровне . Возможно, вы привыкли делать это таким образом на языке, на котором было удобно работать с обоими одновременно, но это совпадение, когда это происходит. Финализация удобна, когда вы не перехватываете все исключения из внутреннего блока. try...with предназначен для перехвата исключений, чтобы вычисления могли продолжаться в обычном режиме. Просто между этими двумя отношениями нет (во всяком случае, они идут в противоположных направлениях: поймали ли вы исключение или позволяете ему пройти?).

  2. Зачем вам вообще что-то дорабатывать? Разве GC не должен управлять ресурсами, на которые нет ссылок? Ах ... но язык пытается дать вам доступ к системным примитивам, которые работают с побочными эффектами, с явным распределением и удалением. Вы должны отменить выделение того, что вы выделили (во всех случаях) ... Разве вы не должны обвинять гнилой интерфейс, который предоставляет система вместо F #, который в данном случае является только мессенджером?

0 голосов
/ 16 января 2010

Но это кажется слишком искусственным, оно ясно демонстрирует, что «F # против try / with / finally». Почему это так?

Полагаю, F # вообще может быть "против" обработки исключений. Ради совместимости .NET он должен поддерживать их, но в основном в функциональном программировании * нет обработки исключений .

Подбрасывание / отлов исключений означает выполнение «прыжков в никуда», которые даже не замечены системой типов, что в корне противоречит философии функциональности.

Вы можете использовать чисто функциональный (монадический) код для переноса исключений. Все ошибки обрабатываются через значения в терминах базовой системы типов и без скачков / побочных эффектов.

Вместо написания функции

let readNumber() : int = ...

, который может выдавать произвольные исключения, вы просто заявите

let readNumber() : int option = ...

, который автоматически очищает эту точку по сигнатуре типа.

* Это не значит, что мы не справляемся с исключительными ситуациями, это просто вид обработки исключений в .NET / C ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...