Tratamento de errosError Handling

O resultado da avaliação de uma expressão do M produz um dos seguintes resultados:The result of evaluating an M expression produces one of the following outcomes:

  • Apenas um valor é produzido.A single value is produced.

  • Um erro é gerado, indicando que o processo de avaliação da expressão não pôde produzir um valor.An error is raised, indicating the process of evaluating the expression could not produce a value. Um erro contém um valor de registro que pode ser usado para fornecer informações adicionais sobre o que causou a avaliação incompleta.An error contains a single record value that can be used to provide additional information about what caused the incomplete evaluation.

Os erros podem ser gerados de dentro de uma expressão e podem ser manipulados de dentro de uma expressão.Errors can be raised from within an expression, and can be handled from within an expression.

Como gerar errosRaising errors

A sintaxe para gerar um erro é a seguinte:The syntax for raising an error is as follows:

expressão-para-geração-de-erros:error-raising-expression:
      error expressão      error expression

Valores de texto podem ser usados como abreviação para valores de erro.Text values can be used as shorthand for error values. Por exemplo:For example:

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

Os valores de erro completos são registros e podem ser construídos usando a função Error.Record:Full error values are records and can be constructed using the Error.Record function:

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

A expressão acima é equivalente a:The above expression is equivalent to:

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

Gerar um erro fará com que a avaliação da expressão atual pare e a pilha de avaliação da expressão se desenrole até que uma das seguintes situações ocorra:Raising an error will cause the current expression evaluation to stop, and the expression evaluation stack will unwind until one of the following occurs:

  • Um campo de registro, um membro de seção ou uma variável let—coletivamente: uma entrada—é alcançada.A record field, section member, or let variable—collectively: an entry—is reached. A entrada está marcada como tendo um erro, o valor do erro é salvo com essa entrada e, em seguida, propagada.The entry is marked as having an error, the error value is saved with that entry, and then propagated. Qualquer acesso subsequente a essa entrada fará com que um erro idêntico seja gerado.Any subsequent access to that entry will cause an identical error to be raised. Outras entradas do registro, da seção ou da expressão let não serão necessariamente afetadas (a menos que acessem uma entrada marcada anteriormente como tendo um erro).Other entries of the record, section, or let expression are not necessarily affected (unless they access an entry previously marked as having an error).

  • A expressão de nível superior é alcançada.The top-level expression is reached. Nesse caso, o resultado da avaliação da expressão de nível superior é um erro em vez de um valor.In this case, the result of evaluating the top-level expression is an error instead of a value.

  • Uma expressão try é alcançada.A try expression is reached. Nesse caso, o erro é capturado e retornado como um valor.In this case, the error is captured and returned as a value.

Gerenciando errosHandling errors

Uma expressão-de-tratamento-de-erro é usada para gerenciar um erro:An error-handling-expression is used to handle an error:

_expressão-de-tratamento-de-erro:_error-handling-expression:
      try expressão-protegida cláusula-otherwiseopt
expressão-protegida:
      expressão
cláusula-otherwise:
      try protected-expression otherwise-clauseopt
protected-expression:
      expression
otherwise-clause:

      otherwise expressão-padrão
expressão-padrão:
      expressão
      otherwise default-expression
default-expression:
      expression

Os seguintes preceitos são válidos ao avaliar uma expressão-de-tratamento-de-erro sem uma cláusula-otherwise:The following holds when evaluating an error-handling-expression without an otherwiseclause:

  • Se a avaliação da expressão-protegida não resultar em um erro e produzir um valor x, o valor produzido pela expressão-de-tratamento-de-erro será um registro com o seguinte formato:If the evaluation of the protected-expression does not result in an error and produces a value x, the value produced by the error-handling-expression is a record of the following form:
    [ HasErrors = false, Value = x ]
  • Se a avaliação da expressão-protegida gerar um valor de erro e o resultado da expressão-de-tratamento-de-erro for um registro com o seguinte formato:If the evaluation of the protected-expression raises an error value e, the result of the error-handling-expression is a record of the following form:
    [ HasErrors = true, Error = e ]

Os seguintes preceitos são válidos ao avaliar uma expressão-de-tratamento-de-erro com uma cláusula-otherwise:The following holds when evaluating an error-handling-expression with an otherwiseclause:

  • A expressão-protegida precisa ser avaliada antes da cláusula-otherwise.The protected-expression must be evaluated before the otherwise-clause.

  • A cláusula-otherwise precisará ser avaliada se e somente se a avaliação da expressão-protegida gerar um erro.The otherwise-clause must be evaluated if and only if the evaluation of the protectedexpression raises an error.

  • Se a avaliação da expressão-protegida gerar um erro, o valor produzido pela expressão-de-tratamento-de-erro será o resultado da avaliação da cláusula-otherwise.If the evaluation of the protected-expression raises an error, the value produced by the error-handling-expression is the result of evaluating the otherwise-clause.

  • Erros gerados durante a avaliação da cláusula-otherwise são propagados.Errors raised during the evaluation of the otherwise-clause are propagated.

O seguinte exemplo ilustra uma expressão-de-tratamento-de-erro em um caso em que nenhum erro é gerado:The following example illustrates an error-handling-expression in a case where no error is raised:

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

Este exemplo mostra como gerar um erro e tratá-lo:The following example shows raising an error and then handling it:

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

Uma cláusula-otherwise pode ser usada para substituir erros gerenciados por uma expressão try com um valor alternativo:An otherwise clause can be used to replace errors handled by a try expression with an alternative value:

try error "A" otherwise 1 
// 1

Se a cláusula-otherwise também gerar um erro, a expressão try inteira fará o mesmo:If the otherwise clause also raises an error, then so does the entire try expression:

try error "A" otherwise error "B" 
// error with message "B"

Erros no registro e inicializadores letErrors in record and let initializers

O exemplo a seguir mostra um inicializador de registro com um campo A que gera um erro e é acessado por dois outros campos, B e C.The following example shows a record initializer with a field A that raises an error and is accessed by two other fields B and C. O campo B não gerencia o erro que é gerado pelo A, mas C o gerencia.Field B does not handle the error that is raised by A, but C does. O campo final D não acessa A e, portanto, não é afetado pelo erro em A.The final field D does not access A and so it is not affected by the error in 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 
]

O resultado da avaliação da expressão acima é:The result of evaluating the above expression is:

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

O tratamento de erro em M deve ser executado próximo à causa de erros para lidar com os efeitos da inicialização de campo lenta e das avaliações de fechamento adiadas.Error handling in M should be performed close to the cause of errors to deal with the effects of lazy field initialization and deferred closure evaluations. O seguinte exemplo mostra uma tentativa malsucedida de tratar um erro usando uma expressão try:The following example shows an unsuccessful attempt at handling an error using a try expression:

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

Neste exemplo, a definição g foi destinada a tratar o erro gerado ao chamar f.In this example, the definition g was meant to handle the error raised when calling f. No entanto, o erro é gerado por um inicializador de campo que só é executado quando necessário. Assim, isso só ocorrerá após o registro ter sido retornado de f e passado pela expressão try.However, the error is raised by a field initializer that only runs when needed and thus after the record was returned from f and passed through the try expression.

Erro "não implementado"Not implemented error

Enquanto uma expressão está sendo desenvolvida, um autor pode querer não incluir a implementação para algumas partes da expressão, mas ainda pode querer ser capaz de executar essa expressão.While an expression is being developed, an author may want to leave out the implementation for some parts of the expression, but may still want to be able to execute the expression. Uma forma de lidar com esse caso é gerar um erro para as partes não implementadas.One way to handle this case is to raise an error for the unimplemented parts. Por exemplo:For example:

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

O símbolo de reticências (...) pode ser usado como um atalho para error.The ellipsis symbol (...) can be used as a shortcut for error.

expressão-não-implementada:not-implemented-expression:
      ...      ...

Por exemplo, o seguinte é equivalente ao exemplo anterior:For example, the following is equivalent to the previous example:

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