Distin guish между исключением и отказом в блоке CATCH [RAKU] - PullRequest
9 голосов
/ 30 января 2020

Мы знаем, что Сбой может быть обработан блоком CATCH.

В следующем примере мы создаем Сбой 'AdHo c' (в другом подпрограмме) и обрабатываем Исключение в CATCH. block (в my-sub)

sub my-sub {
    try {
        CATCH {
            when X::AdHoc { say 'AdHoc Exception handled here'; .resume }
            default {say 'Other Exception'; .resume}
        }

        my $b = other-sub();

        $b.so ?? $b.say !! 'This was a Failure'.say;
    }
}

sub other-sub { fail 'Failure_X' }

my-sub();

Вывод следующий:

AdHoc Exception handled here
This was a Failure

У меня такой вопрос: как мы можем различить guish между Отказом и «нормальное» исключение в блоке CATCH, чтобы различать два случая?

Ответы [ 2 ]

12 голосов
/ 30 января 2020

Отношение между Failure и Exception заключается в том, что Failure имеет Exception, то есть он содержит объект исключения как часть своего состояния. Примерно так:

class Failure {
    has Exception $.exception;
    # ...
}

Когда Failure «взрывается», он делает это, бросая Exception, который находится внутри него. Таким образом, то, что достигает блока CATCH, является объектом Exception, и нет обратной связи с вмещающим Failure. (На самом деле, данный Exception объект в принципе может удерживаться многими Failure с.)

Следовательно, прямого способа обнаружить это нет. С точки зрения дизайна, вы, вероятно, не должны, и должны найти другой способ решения вашей проблемы. Failure - это просто способ отложить генерирование исключения и позволить ему рассматриваться как значение; не предполагается, что природа основной проблемы меняется, потому что она передается как значение, а не как непосредственная передача потока управления. К сожалению, первоначальная цель не была указана в вопросе; вам может быть полезно взглянуть на исключения управления, но в противном случае, возможно, опубликуйте другой вопрос об основной проблеме, которую вы пытаетесь решить. Вероятно, есть лучший способ.

Для полноты отметим, что - это косвенные способы, которыми можно обнаружить, что Exception был брошен Failure. Например, если вы получите .backtrace объекта исключения и посмотрите на пакет верхнего фрейма, можно определить, что он исходит из Failure:

sub foo() { fail X::AdHoc.new(message => "foo") }
try {
    foo();
    CATCH {
        note do { no fatal; .backtrace[0].code.package ~~ Failure };
        .resume
    }
}

Однако это сильно зависит на детали реализации, которые могут легко измениться, поэтому я бы не стал на это полагаться.

6 голосов
/ 30 января 2020

Просто удалите оболочку try:

sub my-sub {

#    try {              <--- remove this line...

        CATCH {
            when X::AdHoc { say 'AdHoc Exception handled here'; .resume }
            default {say 'Other Exception'; .resume}
        }

        my $b = other-sub();

        $b.so ?? $b.say !! 'This was a Failure'.say;

#    }                  <--- ...and this one

}

sub other-sub { fail 'Failure_X' }

my-sub();

Вы использовали try. A try делает несколько вещей, но здесь уместно то, что он говорит Raku немедленно выдвигать любые Failure s в своей области исключений - это то, что вы говорите, что не хотите , Поэтому самое простое решение - просто прекратить это делать.


Этот ответ просто многословно повторяет часть объяснения Джнтна (см., В частности, комментарии, которые он написал ниже своего ответа). Но я не был уверен, что все читатели заметят / поймут этот аспект, и не думал, что один или два комментария к ответу jnthn помогут, следовательно, этот ответ.

Я написал это как ответ сообщества на убедитесь, что я не получу никакой пользы от голосов, потому что это явно не гарантирует этого. Если он получит достаточно голосов, мы просто удалим его.

...