Fejlhåndtering

Resultatet af evalueringen af et M-udtryk giver et af følgende resultater:

  • Der oprettes en enkelt værdi.

  • Der udløses en fejl, der angiver, at evalueringsprocessen for udtrykket ikke kunne give en værdi. En fejl indeholder en enkelt postværdi, der kan bruges til at angive yderligere oplysninger om, hvad der forårsagede den ufuldstændige evaluering.

Fejl kan udløses fra et udtryk og kan håndteres fra et udtryk.

Opløftning af fejl

Syntaksen for at udløse en fejl er som følger:

error-raising-expression:
      errorUdtryk

Tekstværdier kan bruges som en oversigt over fejlværdier. Eksempler:

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

Fulde fejlværdier er poster og kan oprettes ved hjælp af funktionen Error.Record :

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

Ovenstående udtryk svarer til:

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

Hvis der udløses en fejl, stoppes den aktuelle evaluering af udtryk, og evalueringsstakken for udtryk slapper af, indtil en af følgende opstår:

  • Et postfelt, et sektionsmedlem eller en let-variabel – samlet: en post – nås. Posten er markeret som at have en fejl, fejlværdien gemmes sammen med den pågældende post og overføres derefter. Enhver efterfølgende adgang til posten medfører, at der udløses en identisk fejl. Andre poster i posten, sektionen eller let-udtrykket påvirkes ikke nødvendigvis (medmindre de får adgang til en post, der tidligere er markeret som havende en fejl).

  • Udtrykket på øverste niveau nås. I dette tilfælde er resultatet af evalueringen af udtrykket på øverste niveau en fejl i stedet for en værdi.

  • Et try udtryk er nået. I dette tilfælde registreres fejlen og returneres som en værdi.

Håndtering af fejl

Et error-handling-expression (uformelt kaldet et "try-udtryk") bruges til at håndtere en fejl:

error-handling-expression:
      tryprotected-expression error-handleropt
protected-expression:
      Udtryk
error-handler:
      otherwise-clause
      catch-clause
otherwise-clause:

      otherwisestandardudtryk
default-expression:
      Udtryk
catch-clause:
      catchcatch-function
catch-function:
      (parameter-nameopt)=>function-body

Følgende gælder ved evaluering af et error-handling-expression uden en fejlhandler:

  • Hvis evalueringen af protected-expression ikke resulterer i en fejl og opretter en værdi x, er den værdi, der oprettes af error-handling-expression, en post i følgende formular:
    [ HasErrors = false, Value = x ]
  • Hvis evalueringen af protected-expression udløser en fejlværdi e, er resultatet af error-handling-expression en post i følgende formular:
    [ HasErrors = true, Error = e ]

Følgende gælder ved evaluering af et error-handling-expression med en fejlhandler:

  • Protected-expression skal evalueres før fejlhandleren.

  • Fejlhandleren skal evalueres, hvis og kun hvis evalueringen af protected-expression udløser en fejl.

  • Hvis evalueringen af protected-expression udløser en fejl, er den værdi, der oprettes af error-handling-expression, resultatet af evalueringen af fejlhandleren.

  • Fejl, der udløses under evalueringen af fejlhandleren , overføres.

  • Når den fejlhandler, der evalueres, er en catch-clause, aktiveres catch-funktionen . Hvis denne funktion accepterer en parameter, overføres fejlværdien som dens værdi.

I følgende eksempel illustreres et error-handling-expression i et tilfælde, hvor der ikke udløses nogen fejl:

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

I følgende eksempel kan du se, hvordan der udløses en fejl, og hvordan den derefter håndteres:

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

Det foregående eksempel kan omskrives med mindre syntaks ved hjælp af en catch-clause med en catch-function , der accepterer en parameter:

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

En otherwise-clause kan bruges til at erstatte fejl, der håndteres af et try-udtryk, med en alternativ værdi:

try error "A" otherwise 1 
// 1

En catch-clause med en catch-function med nul-parameter er reelt en længere, alternativ syntaks for en otherwise-clause:

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

Hvis fejlhandleren også udløser en fejl, så gør hele try-udtrykket det også:

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"

Fejl i post og lad initialisering

I følgende eksempel vises en postinitialiseringsfunktion med et felt A , der udløser en fejl og åbnes af to andre felter B og C. Feltet B håndterer ikke den fejl, der udløses af A, men C gør. Det endelige felt D har ikke adgang til A , og det påvirkes derfor ikke af fejlen i A.

[ 
    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 
]

Resultatet af evalueringen af ovenstående udtryk er:

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

Fejlhåndtering i M skal udføres tæt på årsagen til fejl for at håndtere virkningerne af doven feltinitialisering og udskudte lukningsevalueringer. I følgende eksempel vises et mislykket forsøg på at håndtere en fejl ved hjælp af et try udtryk:

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

I dette eksempel var definitionen g beregnet til at håndtere den fejl, der opstod under kald af f. Fejlen udløses dog af en feltinitialiseringsfunktion, der kun kører, når det er nødvendigt, og dermed efter at posten blev returneret fra f og sendt gennem try udtrykket.

Fejl, der ikke er implementeret

Mens der udvikles et udtryk, vil en forfatter muligvis udelade implementeringen for nogle dele af udtrykket, men vil måske stadig kunne udføre udtrykket. En måde at håndtere denne sag på er ved at udløse en fejl for de ikke-implementerede dele. Eksempler:

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

Ellipsesymbolet (...) kan bruges som genvej til error.

not-implemented-expression:
      ...

Følgende svarer f.eks. til det forrige eksempel:

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