Исключение управления scala 2.8 - какой смысл?

Можно прочитать Emacs-связанные страницы по PortableApps.com , и если они еще не портировали Emacs к своему набору портативных приложений, затем попросите, чтобы они любезно добавили Emacs к списку текстовые редакторы . С достаточным количеством запросов они сделают это в конечном счете.

21
задан oxbow_lakes 29 October 2009 в 20:14
поделиться

3 ответа

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

Парадигма try / catch , используемая в C ++ и Java, в значительной степени относится к первому типу (*).

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

Следовательно, на языке, который претендует на поддержку как функционального, так и объектно-ориентированного стиля, не следует удивляться, увидев поддержку библиотеки для лечения исключения как данные.

И обратите внимание, что существует очень много других возможностей, предоставляемых Exception для обработки вещей. Вы можете, например, обработчики цепных захватов, во многом так же, как функции Lift chain partial, чтобы упростить делегирование ответственности за обработку запросов веб-страниц.

Вот один пример того, что можно сделать, поскольку автоматическое управление ресурсами сейчас в моде:

def arm[T <: java.io.Closeable,R](resource: T)(body: T => R)(handlers: Catch[R]):R = (
  handlers 
  andFinally (ignoring(classOf[Any]) { resource.close() }) 
  apply body(resource)
)

Это дает вам безопасное закрытие ресурса (обратите внимание на использование игнорирования) и по-прежнему применяет любую логику перехвата, которую вы, возможно, захотите использовать.

(*) Любопытно, что контроль исключений Форта, catch & throw , представляет собой их смесь. Поток переходит от throw к catch , но затем эта информация обрабатывается как данные.

EDIT

Хорошо, хорошо, я уступаю. Приведу пример. ОДИН пример, и все! Надеюсь, это не слишком надумано, но выхода нет. Такие вещи были бы наиболее полезны в больших фреймворках, не небольшими выборками.

В любом случае, давайте сначала определим что-нибудь, что связано с ресурсом. Я решил печатать строки и возвращать количество напечатанных строк, и вот код:

def linePrinter(lnr: java.io.LineNumberReader) = arm(lnr) { lnr =>
  var lineNumber = 0
  var lineText = lnr.readLine()
  while (null != lineText) {
    lineNumber += 1
    println("%4d: %s" format (lineNumber, lineText))
    lineText = lnr.readLine()
  }
  lineNumber
} _

Вот тип этой функции:

linePrinter: (lnr: java.io.LineNumberReader)(util.control.Exception.Catch[Int]) => Int

Итак, arm получил общий Closeable, но мне нужно a LineNumberReader, поэтому, когда я вызываю эту функцию, мне нужно передать ее. Однако я возвращаю функцию Catch [Int] => Int , что означает, что мне нужно передать два параметра в linePrinter , чтобы заставить его работать. Давайте придумаем Reader , теперь:

val functionText = """def linePrinter(lnr: java.io.LineNumberReader) = arm(lnr) { lnr =>
  var lineNumber = 1
  var lineText = lnr.readLine()
  while (null != lineText) {
    println("%4d: %s" format (lineNumber, lineText))
    lineNumber += 1
    lineText = lnr.readLine()
  }
  lineNumber
} _"""

val reader = new java.io.LineNumberReader(new java.io.StringReader(functionText))

Итак, теперь давайте воспользуемся им. Сначала простой пример:

scala> linePrinter(new java.io.LineNumberReader(reader))(noCatch)
   1: def linePrinter(lnr: java.io.LineNumberReader) = arm(lnr) { lnr =>
   2:          var lineNumber = 1
   3:          var lineText = lnr.readLine()
   4:          while (null != lineText) {
   5:            println("%4d: %s" format (lineNumber, lineText))
   6:            lineNumber += 1
   7:            lineText = lnr.readLine()
   8:          }
   9:          lineNumber
  10:        } _
res6: Int = 10

И если я попробую еще раз, то получу следующее:

scala> linePrinter(new java.io.LineNumberReader(reader))(noCatch)
java.io.IOException: Stream closed

Теперь предположим, что я хочу вернуть 0, если произойдет какое-либо исключение. Я могу это сделать так:

linePrinter(new java.io.LineNumberReader(reader))(allCatch withApply (_ => 0))

What ' Здесь интересно то, что я полностью отделил обработку исключений (часть catch в try / catch ) от закрытия ресурса , что выполняется через , наконец, . Кроме того, обработка ошибок - это значение, которое я могу передать функции. По крайней мере, это значительно упрощает издевательство над операторами try / catch / finally . : -)

Кроме того, я могу объединить несколько Catch с помощью метода или , чтобы разные уровни моего кода могли добавлять разные обработчики для разных исключений. Это действительно моя основная мысль, но я не смог найти интерфейс с богатым исключениями (за то короткое время, которое я посмотрел :).

I ' Завершу замечанием по поводу данного мной определения руки . Это нехорошо. В частности, я не могу использовать методы Catch , такие как toEither или toOption , чтобы изменить результат с R на что-то другое, что серьезно уменьшает значение использования в нем Catch . Однако я не знаю, как это изменить.

28
ответ дан 29 November 2019 в 20:39
поделиться

Я бы сказал, что это прежде всего вопрос стиля выражения.

Помимо того, что новый метод catching () короче своего эквивалента, он предлагает более функциональный способ выразить то же поведение. Операторы try ... catch обычно считаются императивным стилем, а исключения - побочными эффектами. Catching () накладывает покров на этот императивный код, чтобы скрыть его от просмотра.

Что еще более важно, теперь, когда у нас есть функция, ее легче скомпоновать с другими вещами; его можно передать другим функциям более высокого порядка для создания более сложного поведения. (Вы не можете напрямую передать оператор try .. catch с параметризованным типом исключения.)

Другой способ взглянуть на это - если Scala не предлагала эту функцию catching (). Тогда, скорее всего, люди будут заново изобретать его самостоятельно, что приведет к дублированию кода, и приводят к более нестандартному коду. Поэтому я думаю, что дизайнеры Scala считают, что эта функция достаточно распространена, чтобы гарантировать включение ее в стандартную библиотеку Scala. (И я согласен)

alex

3
ответ дан 29 November 2019 в 20:39
поделиться

As the guy who wrote it, the reasons are composition and encapsulation. The scala compiler (and I am betting most decent sized source bases) is littered with places which swallow all exceptions -- you can see these with -Ywarn-catches -- because the programmer is too lazy to enumerate the relevant ones, which is understandable because it's annoying. By making it possible to define, re-use, and compose catch and finally blocks independently of the try logic, I hoped to lower the barrier to writing sensible blocks.

And, it's not exactly finished, and I'm working on a million other areas too. If you look through the actors code you can see examples of huge cut-and-pasted multiply-nested try/catch/finally blocks. I was/am unwilling to settle for try { catch { try { catch { try { catch ...

My eventual plan is to have catch take an actual PartialFunction rather than require a literal list of case statements, which presents a whole new level of opportunity, i.e. try foo() catch getPF()

9
ответ дан 29 November 2019 в 20:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: