Sdílet prostřednictvím


Zpracování chyb

Výsledkem vyhodnocení výrazu M je jeden z následujících výsledků:

  • Vytvoří se jedna hodnota.

  • Vyvolá se chyba, která značí, že proces vyhodnocení výrazu nemohl vytvořit hodnotu. Chyba obsahuje jednu hodnotu záznamu, kterou lze použít k poskytnutí dalších informací o tom, co způsobilo neúplné vyhodnocení.

Chyby mohou být vyvolány z výrazu a lze je zpracovat z výrazu.

Vyvolávání chyb

Syntaxe pro vyvolání chyby je následující:

error-raising-expression:
      error výraz

Textové hodnoty lze použít jako zkratku pro chybové hodnoty. Příklad:

error "Hello, world" // error with message "Hello, world"

Úplné chybové hodnoty jsou záznamy a lze je vytvořit pomocí Error.Record funkce:

error Error.Record("FileNotFound", "File my.txt not found",
     "my.txt")

Výše uvedený výraz je ekvivalentní:

error [ 
    Reason = "FileNotFound", 
    Message = "File my.txt not found", 
    Detail = "my.txt" 
]

Vyvolání chyby způsobí zastavení vyhodnocení aktuálního výrazu a zásobník vyhodnocení výrazu se uvolní, dokud nedojde k některé z následujících situací:

  • Bylo dosaženo pole záznamu, člena oddílu nebo proměnné let ( souhrnně: záznam). Položka je označena jako chyba, chybová hodnota se uloží s danou položkou a pak se rozšíří. Jakýkoli následný přístup k této položce způsobí vyvolání stejné chyby. Jiné položky záznamu, oddílu nebo výrazu let nemusí být nutně ovlivněny (pokud nepřistupují k položce, která byla dříve označena jako chyba).

  • Byl dosažen výraz nejvyšší úrovně. V tomto případě je výsledkem vyhodnocení výrazu nejvyšší úrovně chyba místo hodnoty.

  • Byl try dosažen výraz. V tomto případě se chyba zachytí a vrátí jako hodnota.

Zpracování chyb

Výraz pro zpracování chyb (neformálně označovaný jako výraz try) slouží ke zpracování chyby:

error-handling-expression:
      tryopt obslužné rutiny chyby chráněného výrazu
protected-expression:
      výraz
obslužná rutina chyby:
      otherwise-clause
      catch-clause
otherwise-clause:

      otherwisedefault-expression
default-expression:
      výraz
catch-clause:
      catchcatch-function
catch-function:
      (parametr-nameopt) => function-body

Při vyhodnocování výrazu zpracování chyb bez obslužné rutiny chyby platí následující:

  • Pokud vyhodnocení chráněného výrazu nemá za následek chybu a vygeneruje hodnotu x, je hodnota vytvořená výrazem zpracování chyb záznamem následujícího formuláře:
    [ HasErrors = false, Value = x ]
  • Pokud vyhodnocení chráněného výrazu vyvolá chybovou hodnotu e, výsledek výrazu zpracování chyb je záznamem následujícího formuláře:
    [ HasErrors = true, Error = e ]

Při vyhodnocování výrazu zpracování chyb s obslužnou rutinou chyby platí následující:

  • Chráněný výraz musí být vyhodnocen před obslužnou rutinou chyby.

  • Obslužná rutina chyby musí být vyhodnocena, pokud a pouze v případě, že vyhodnocení chráněného výrazu vyvolá chybu.

  • Pokud vyhodnocení chráněného výrazu vyvolá chybu, hodnota vytvořená výrazem error-handling-expression je výsledkem vyhodnocení obslužné rutiny chyby.

  • Chyby vyvolané při vyhodnocování obslužné rutiny chyby se šíří.

  • Při vyhodnocování obslužné rutiny chyby je catch-klauzule, vyvolá se funkce catch. Pokud tato funkce přijme parametr, bude chybová hodnota předána jako její hodnota.

Následující příklad znázorňuje výraz zpracování chyb v případě, že není vyvolána žádná chyba:

let
    x = try "A"
in
    if x[HasError] then x[Error] else x[Value] 
// "A"

Následující příklad ukazuje vyvolání chyby a následné zpracování:

let
    x = try error "A" 
in
    if x[HasError] then x[Error] else x[Value] 
// [ Reason = "Expression.Error", Message = "A", Detail = null ]

Předchozí příklad lze přepsat s menší syntaxí pomocí klauzule catch s funkcí catch, která přijímá parametr:

let
    x = try error "A" catch (e) => e
in
    x
// [ Reason = "Expression.Error", Message = "A", Detail = null ]

K nahrazení chyb zpracovaných výrazem try s alternativní hodnotou lze použít klauzuli otherwise-clause :

try error "A" otherwise 1 
// 1

Klauzule catch s funkcí catch-function s nulovým parametrem je efektivně delší a alternativní syntaxe klauzule otherwise-clause:

try error "A" catch () => 1 
// 1

Pokud obslužná rutina chyby vyvolá také chybu, provede se tak celý výraz try:

try error "A" otherwise error "B" 
// error with message "B"
try error "A" catch () => error "B" 
// error with message "B"
try error "A" catch (e) => error "B" 
// error with message "B"

Chyby v inicializátorech záznamů a let

Následující příklad ukazuje inicializátor záznamů s polem A , které vyvolá chybu a je přístupné dvěma dalšími poli B a C. Pole B nezpracuje chybu, která je vyvolána A, ale C dělá. Konečné pole D nemá přístup a A proto není ovlivněno chybou v Asouboru .

[ 
    A = error "A", 
    B = A + 1,
    C = let x =
            try A in
                if not x[HasError] then x[Value]
                else x[Error], 
    D = 1 + 1 
]

Výsledkem vyhodnocení výše uvedeného výrazu je:

[ 
    A = // error with message "A" 
    B = // error with message "A" 
    C = "A", 
    D = 2 
]

Zpracování chyb v jazyce M by mělo být provedeno blízko příčiny chyb, aby se vyřešily účinky opožděné inicializace polí a odložené vyhodnocení uzavření. Následující příklad ukazuje neúspěšný pokus o zpracování chyby pomocí výrazu try :

let
    f = (x) => [ a = error "bad", b = x ],
    g = try f(42) otherwise 123
in 
    g[a]  // error "bad"

V tomto příkladu byla definice g určena ke zpracování chyby vyvolané při volání f. Chyba je však vyvolána inicializátorem pole, který se spustí pouze v případě potřeby, a proto po vrácení záznamu z f a předání výrazem try .

Chyba neimplementovaná

Zatímco se vyvíjí výraz, autor může chtít vynechat implementaci některých částí výrazu, ale přesto může chtít, aby mohl výraz spustit. Jedním ze způsobů, jak tento případ zpracovat, je vyvolat chybu pro neplementované části. Příklad:

(x, y) =>
     if x > y then
         x - y
     else
         error Error.Record("Expression.Error", 
            "Not Implemented")

Symbol tří teček (...) lze použít jako zástupce pro error.

neimplementovaný výraz:
      ...

Následující příklad například odpovídá předchozímu příkladu:

(x, y) => if x > y then x - y else ...