Comportamento do operador
Esta seção define o comportamento dos vários operadores M.
Precedência dos operadores
Quando uma expressão contém vários operadores, a precedência dos operadores controla a ordem na qual os operadores individuais são avaliados. Por exemplo, a expressão x + y * z
é avaliada como x + (y * z)
porque o *
operador tem maior precedência do que o operador binário +
. A precedência de um operador é estabelecida pela definição da sua produção gramatical associada. Por exemplo, uma expressão aditiva consiste em uma sequência de expressões multiplicativas separadas por +
ou -
operadores, dando assim aos +
operadores e -
menor precedência do que os *
operadores e /
.
A produção de expressão entre parênteses pode ser usada para alterar a ordem de precedência padrão.
expressão entre parênteses:
(
expressão)
Por exemplo:
1 + 2 * 3 // 7
(1 + 2) * 3 // 9
A tabela a seguir resume os operadores M, listando as categorias de operadores em ordem de precedência do mais alto para o mais baixo. Os operadores da mesma categoria têm igual precedência.
Categoria | Expression | Description |
---|---|---|
Primário |
eu @ eu |
Expressão do identificador |
x) | Expressão entre parênteses | |
x[i] | Procura | |
x{y} | Acesso ao item | |
x(...) | Invocação de função | |
{x, y, ...} | Inicialização da lista | |
[ i = x, ... ] | Inicialização de registros | |
... | Não implementado | |
Unário | + x | Identidade |
- x | Negação | |
not
x |
Negação lógica | |
Metadados |
xmeta y |
Associar metadados |
Multiplicativo | x * y | Multiplicação |
x / y | Divisão | |
Aditivo | x + y | Adição |
x - y | Subtração | |
Relacional | x< y | Menor que |
x > y | Maior que | |
x<= y | Menor ou igual a | |
x >= y | Maior ou igual a | |
Equality | x = y | Igual |
x<> y | Não é igual a | |
Asserção de tipo |
xas y |
É compatível tipo primitivo nulo ou erro |
Conformidade com o tipo |
xis y |
Teste se o tipo de primitiva nula compatível |
Lógica E |
xand y |
Conjunção de curto-circuito |
Lógica OU |
xor y |
Disjunção de curto-circuito |
Coalesce |
x?? y |
Operador coalescente nulo |
Operadores e metadados
Cada valor tem um valor de registro associado que pode conter informações adicionais sobre o valor. Esse registro é conhecido como o registro de metadados para um valor. Um registro de metadados pode ser associado a qualquer tipo de valor, até mesmo null
. O resultado dessa associação é um novo valor com os metadados fornecidos.
Um registro de metadados é apenas um registro regular e pode conter quaisquer campos e valores que um registro regular pode, e ele próprio tem um registro de metadados. Associar um registro de metadados a um valor é "não intrusivo". Ele não altera o comportamento do valor em avaliações, exceto aquelas que inspecionam explicitamente os registros de metadados.
Cada valor tem um registro de metadados padrão, mesmo que um não tenha sido especificado. O registro de metadados padrão está vazio. Os exemplos a seguir mostram o acesso ao registro de metadados de um valor de texto usando a Value.Metadata
função de biblioteca padrão:
Value.Metadata( "Mozart" ) // []
Os registros de metadados geralmente não são preservados quando um valor é usado com um operador ou função que constrói um novo valor. Por exemplo, se dois valores de texto forem concatenados usando o &
operador, os metadados do valor de texto resultante serão o registro []
vazio. As seguintes expressões são equivalentes:
"Amadeus " & ("Mozart" meta [ Rating = 5 ])
"Amadeus " & "Mozart"
A biblioteca padrão funciona Value.RemoveMetadata
e Value.ReplaceMetadata
pode ser usada para remover todos os metadados de um valor e substituir os metadados de um valor (em vez de mesclar metadados em metadados possivelmente existentes).
O único operador que retorna resultados que carregam metadados é o operador meta.
Operadores estruturalmente recursivos
Os valores podem ser cíclicos. Por exemplo:
let l = {0, @l} in l
// {0, {0, {0, ... }}}
[A={B}, B={A}]
// [A = {{ ... }}, B = {{ ... }}]
M lida com valores cíclicos mantendo a construção de registros, listas e tabelas preguiçosa. Uma tentativa de construir um valor cíclico que não se beneficia de valores estruturados preguiçosos interjeitados produz um erro:
[A=B, B=A]
// [A = Error.Record("Expression.Error",
// "A cyclic reference was encountered during evaluation"),
// B = Error.Record("Expression.Error",
// "A cyclic reference was encountered during evaluation"),
// ]
Alguns operadores em M são definidos por recursão estrutural. Por exemplo, a igualdade de registros e listas é definida pela igualdade conjugada de campos de registro e listas de itens correspondentes, respectivamente.
Para valores não cíclicos, a aplicação da recursão estrutural produz uma expansão finita do valor: valores aninhados compartilhados serão percorridos repetidamente, mas o processo de recursão sempre termina.
Um valor cíclico tem uma expansão infinita ao aplicar a recursão estrutural. A semântica de M não faz nenhuma acomodação especial para tais expansões infinitas – uma tentativa de comparar valores cíclicos para igualdade, por exemplo, normalmente ficará sem recursos e terminará excepcionalmente.
Operadores de Seleção e Projeção
Os operadores de seleção e projeção permitem extrair dados de valores de lista e registro.
Acesso ao Item
Um valor pode ser selecionado de uma lista ou tabela com base em sua posição baseada em zero dentro dessa lista ou tabela usando uma expressão de acesso ao item.
item-access-expression:
seleção de itens
opcional-item-seleção
seleção de itens:
seletor de item de expressão{
primária}
opcional-item-seleção:
seletor de item de expressão{
primária} ?
seletor de itens:
expressão
A expressão item-access-retornax{y}
:
Para uma lista
x
e um númeroy
, o item da listax
na posiçãoy
. Considera-se que o primeiro item de uma lista tem um índice ordinal de zero. Se a posição solicitada não existir na lista, é gerado um erro.Para uma tabela
x
e um númeroy
, a linha da tabelax
na posiçãoy
. Considera-se que a primeira linha de uma tabela tem um índice ordinal de zero. Se a posição solicitada não existir na tabela, um erro será gerado.Para uma tabela
x
e um registroy
, a linha da tabelax
que corresponde aos valores de campo de registroy
para campos com nomes de campo que correspondem aos nomes de colunas de tabela correspondentes. Se não houver nenhuma linha correspondente exclusiva na tabela, um erro será gerado.
Por exemplo:
{"a","b","c"}{0} // "a"
{1, [A=2], 3}{1} // [A=2]
{true, false}{2} // error
#table({"A","B"},{{0,1},{2,1}}){0} // [A=0,B=1]
#table({"A","B"},{{0,1},{2,1}}){[A=2]} // [A=2,B=1]
#table({"A","B"},{{0,1},{2,1}}){[B=3]} // error
#table({"A","B"},{{0,1},{2,1}}){[B=1]} // error
A expressão item-access-também suporta o formulário x{y}?
, que retorna null
quando a posição (ou correspondência) y
não existe na lista ou tabela x
. Se houver várias correspondências para y
o , um erro ainda será gerado.
Por exemplo:
{"a","b","c"}{0}? // "a"
{1, [A=2], 3}{1}? // [A=2]
{true, false}{2}? // null
#table({"A","B"},{{0,1},{2,1}}){0}? // [A=0,B=1]
#table({"A","B"},{{0,1},{2,1}}){[A=2]}? // [A=2,B=1]
#table({"A","B"},{{0,1},{2,1}}){[B=3]}? // null
#table({"A","B"},{{0,1},{2,1}}){[B=1]}? // error
O acesso ao item não força a avaliação de itens de lista ou tabela diferentes daquele que está sendo acessado. Por exemplo:
{ error "a", 1, error "c"}{1} // 1
{ error "a", error "b"}{1} // error "b"
O seguinte vale quando o operador x{y}
de acesso ao item é avaliado:
Erros levantados durante a avaliação de expressões
x
ouy
são propagados.A expressão
x
produz uma lista ou um valor de tabela.A expressão
y
produz um valor numérico ou, sex
produzir um valor de tabela, um valor de registro.Se
y
produzir um valor numérico e o valor de for negativo, um erro com o códigoy
de"Expression.Error"
razão será gerado.Se
y
produzir um valor numérico e o valor de for maior ou igual à contagem de , um erro com o códigoy
dex
razão será gerado, a menos que o formulário"Expression.Error"
dex{y}?
operador opcional seja usado, caso em que o valornull
será retornado.Se
x
produzir um valor de tabela ey
produzir um valor de registro e não houver correspondências paray
emx
, um erro com código"Expression.Error"
de motivo será gerado, a menos que o formuláriox{y}?
de operador opcional seja usado, caso em que o valornull
será retornado.Se
x
produzir um valor de tabela ey
produzir um valor de registro e houver várias correspondências paray
emx
, um erro com código"Expression.Error"
de motivo será gerado.
Nenhum item x
além daquele na posição y
é avaliado durante o processo de seleção de itens. (Para listas ou tabelas de streaming, os itens ou linhas que precedem a posição y
são ignorados, o que pode causar sua avaliação, dependendo da fonte da lista ou tabela.)
Acesso ao campo
A expressão field-access-é usada para selecionar um valor de um registro ou para projetar um registro ou tabela em um com menos campos ou colunas, respectivamente.
campo-acesso-expressão:
seleção de campo
implicit-target-field-selection
projeção
implicitidade-alvo-projeção
seleção de campos:
seletor de campo de expressão primária
seletor de campo:
seletor de campo obrigatório
opcional-campo-seletor
seletor de campos obrigatórios:
[
nome do campo]
opcional-campo-seletor:
[
nome do campo] ?
nome do campo:
identificador generalizado
identificador cotado
seleção implícita-alvo-campo:
seletor de campo
Projeção:
projeção necessária de expressão primária
expressão primária-opcional-projeção
Projeção necessária:
[
lista de seletores obrigatórios ]
Opcional-Projeção:
[
lista de seletores obrigatórios ] ?
lista de seletores obrigatórios:
seletor de campo obrigatório
required-selector-list,
required-field-selector
implicitidade-alvo-projeção:
projeção necessária
opcional-projeção
A forma mais simples de acesso ao campo é a seleção de campos obrigatórios. Ele usa o operador x[y]
para procurar um campo em um registro por nome de campo. Se o campo y
não existir no x
, um erro será gerado. O formulário x[y]?
é usado para executar a seleção de campo opcional e retorna null
se o campo solicitado não existir no registro.
Por exemplo:
[A=1,B=2][B] // 2
[A=1,B=2][C] // error
[A=1,B=2][C]? // null
O acesso coletivo de vários campos é suportado pelos operadores para projeção de registro necessária e projeção de registro opcional. O operador x[[y1],[y2],...]
projeta o registro em um novo registro com menos campos (selecionado por y1
, y2
, ...
). Se um campo selecionado não existir, um erro será gerado. O operador x[[y1],[y2],...]?
projeta o registro em um novo registro com os campos selecionados por y1
, y2
, ...
; se um campo estiver faltando, null
é usado em vez disso.
Por exemplo:
[A=1,B=2][[B]] // [B=2]
[A=1,B=2][[C]] // error
[A=1,B=2][[B],[C]]? // [B=2,C=null]
Os formulários [y]
e [y]?
são suportados como uma referência abreviada para o identificador _
(sublinhado). As duas expressões seguintes são equivalentes:
[A]
_[A]
O exemplo a seguir ilustra a forma abreviada de acesso ao campo:
let _ = [A=1,B=2] in [A] //1
A forma [[y1],[y2],...]
e [[y1],[y2],...]?
também são suportados como uma abreviatura e as duas expressões a seguir são igualmente equivalentes:
[[A],[B]]
_[[A],[B]]
A forma abreviada é particularmente útil em combinação com a taquigrafia each
, uma maneira de introduzir uma função de um único parâmetro chamado _
(para detalhes, consulte Declarações simplificadas). Juntas, as duas mãos curtas simplificam expressões funcionais comuns de ordem superior:
List.Select( {[a=1, b=1], [a=2, b=4]}, each [a] = [b])
// {[a=1, b=1]}
A expressão acima é equivalente à seguinte longhand de aparência mais enigmática:
List.Select( {[a=1, b=1], [a=2, b=4]}, (_) => _[a] = _[b])
// {[a=1, b=1]}
O acesso ao campo não obriga à avaliação de campos diferentes do(s) acedido(s). Por exemplo:
[A=error "a", B=1, C=error "c"][B] // 1
[A=error "a", B=error "b"][B] // error "b"
O seguinte é válido quando um operador x[y]
de acesso a campo , x[y]?
, x[[y]]
, ou x[[y]]?
é avaliado:
Os erros levantados durante a avaliação da expressão
x
são propagados.Os erros gerados durante a avaliação do campo
y
são permanentemente associados ao campoy
e, em seguida, propagados. Qualquer acesso futuro ao campoy
gerará o mesmo erro.A expressão
x
produz um valor de registro ou tabela, ou um erro é gerado.Se o identificador
y
nomear um campo que não existe nox
, um erro com o código"Expression.Error"
de motivo será gerado, a menos que o formulário...?
de operador opcional seja usado, caso em que o valornull
será retornado.
Nenhum campo diferente daquele x
nomeado por y
é avaliado durante o processo de acesso ao campo.
Operador de metadados
O registro de metadados para um valor é alterado usando o operador meta (x meta y
).
expressão de metadados:
unário-expressão
unary-expressionmeta
unary-expression
O exemplo a seguir constrói um valor de texto com um registro de metadados usando o meta
operador e, em seguida, acessa o registro de metadados do valor resultante usando Value.Metadata
:
Value.Metadata( "Mozart" meta [ Rating = 5 ] )
// [Rating = 5 ]
Value.Metadata( "Mozart" meta [ Rating = 5 ] )[Rating]
// 5
O seguinte vale ao aplicar o operador x meta y
de combinação de metadados:
Os erros gerados ao avaliar as
x
expressões ouy
são propagados.A
y
expressão deve ser um registro ou um erro com o código"Expression.Error"
de razão é gerado.O registro de metadados resultante é
x
o registro de metadados do mesclado comy
o . (Para a semântica da mesclagem de registros, consulte Mesclagem de registros.)O valor resultante é o
x
valor da expressão, sem seus metadados, com o registro de metadados recém-computado anexado.
A biblioteca padrão funciona Value.RemoveMetadata
e Value.ReplaceMetadata
pode ser usada para remover todos os metadados de um valor e substituir os metadados de um valor (em vez de mesclar metadados em metadados possivelmente existentes). As seguintes expressões são equivalentes:
x meta y
Value.ReplaceMetadata(x, Value.Metadata(x) & y)
Value.RemoveMetadata(x) meta (Value.Metadata(x) & y)
Operadores de igualdade
O operador=
de igualdade é usado para determinar se dois valores são iguais. O operador<>
de desigualdade é usado para determinar se dois valores não são iguais.
igualdade-expressão:
expressão-relacional
relacional-expressão=
igualdade-expressão
relacional-expressão<>
igualdade-expressão
Por exemplo:
1 = 1 // true
1 = 2 // false
1 <> 1 // false
1 <> 2 // true
null = true // false
null = null // true
Os metadados não fazem parte da comparação de igualdade ou desigualdade. Por exemplo:
(1 meta [ a = 1 ]) = (1 meta [ a = 2 ]) // true
(1 meta [ a = 1 ]) = 1 // true
O seguinte se aplica ao aplicar os operadores x = y
de igualdade e x <> y
:
Os erros gerados ao avaliar as
x
expressões ouy
são propagados.O
=
operador tem um resultado de se os valores são iguais, etrue
defalse
outra forma.O
<>
operador tem um resultado de se os valores são iguais, efalse
detrue
outra forma.Os registos de metadados não são incluídos na comparação.
Se os valores produzidos pela avaliação das
x
expressões ey
não são o mesmo tipo de valor, então os valores não são iguais.Se os valores produzidos pela avaliação da
x
expressão ey
são do mesmo tipo de valor, então existem regras específicas para determinar se eles são iguais, conforme definido abaixo.O seguinte é sempre verdadeiro:
(x = y) = not (x <> y)
Os operadores de igualdade são definidos para os seguintes tipos:
- O
null
valor é apenas igual a si mesmo.
null = null // true
null = true // false
null = false // false
- Os valores
true
lógicos efalse
são apenas iguais a si mesmos. Por exemplo:
true = true // true
false = false // true
true = false // false
true = 1 // false
Os números são comparados utilizando a precisão especificada:
Se um dos números for
#nan
, então os números não são os mesmos.Quando nenhum dos números é
#nan
, então os números são comparados usando uma comparação bit a bit do valor numérico.#nan
é o único valor que não é igual a si mesmo.Por exemplo:
1 = 1, // true
1.0 = 1 // true
2 = 1 // false
#nan = #nan // false
#nan <> #nan // true
Duas durações são iguais se representarem o mesmo número de carrapatos de 100 nanossegundos.
Duas vezes são iguais se as magnitudes de suas partes (hora, minuto, segundo) forem iguais.
Duas datas são iguais se as magnitudes de suas partes (ano, mês, dia) forem iguais.
Dois datetimes são iguais se as magnitudes de suas partes (ano, mês, dia, hora, minuto, segundo) forem iguais.
Dois fusos datetime são iguais se as datetimes UTC correspondentes forem iguais. Para chegar ao datetime UTC correspondente, o deslocamento de horas/minutos é subtraído do componente datetime do datetimezone.
Dois valores de texto são iguais se, usando uma comparação ordinal, sensível a maiúsculas e minúsculas e sem distinção de cultura, eles tiverem o mesmo comprimento e caracteres iguais nas posições correspondentes.
Dois valores de lista serão iguais se todos os itens a seguir forem verdadeiros:
Ambas as listas contêm o mesmo número de itens.
Os valores de cada item correspondente posicionalmente nas listas são iguais. Isso significa que não apenas as listas precisam conter itens iguais, mas os itens precisam estar na mesma ordem.
Por exemplo:
{1, 2} = {1, 2} // true {2, 1} = {1, 2} // false {1, 2, 3} = {1, 2} // false
Dois registros serão iguais se todos os itens a seguir forem verdadeiros:
O número de campos é o mesmo.
Cada nome de campo de um registro também está presente no outro registro.
O valor de cada campo de um registo é igual ao campo com o mesmo nome no outro registo.
Por exemplo:
[ A = 1, B = 2 ] = [ A = 1, B = 2 ] // true [ B = 2, A = 1 ] = [ A = 1, B = 2 ] // true [ A = 1, B = 2, C = 3 ] = [ A = 1, B = 2 ] // false [ A = 1 ] = [ A = 1, B = 2 ] // false
Duas tabelas são iguais se todas as seguintes opções forem verdadeiras:
O número de colunas é o mesmo.
Cada nome de coluna em uma tabela também está presente na outra tabela.
O número de linhas é o mesmo.
Cada linha tem valores iguais nas células correspondentes.
Por exemplo:
#table({"A","B"},{{1,2}}) = #table({"A","B"},{{1,2}}) // true #table({"A","B"},{{1,2}}) = #table({"X","Y"},{{1,2}}) // false #table({"A","B"},{{1,2}}) = #table({"B","A"},{{2,1}}) // true
Um valor de função é igual a si mesmo, mas pode ou não ser igual a outro valor de função. Se dois valores de função forem considerados iguais, eles se comportarão de forma idêntica quando invocados.
Dois valores de função dados terão sempre a mesma relação de igualdade.
Um valor de tipo é igual a si mesmo, mas pode ou não ser igual a outro valor de tipo. Se dois valores de tipo forem considerados iguais, eles se comportarão de forma idêntica quando consultados quanto à conformidade.
Dois valores de tipo dados terão sempre a mesma relação de igualdade.
Operadores relacionais
Os <
operadores , >
, <=
, e >=
são chamados de operadores relacionais.
expressão-relacional:
expressão-aditiva
expressão-aditiva-relacional-expressão<
expressão-aditiva-relacional-expressão>
expressão-aditiva-relacional-expressão<=
expressão-aditiva-relacional-expressão>=
Esses operadores são usados para determinar a relação de ordenação relativa entre dois valores, conforme mostrado na tabela a seguir:
Operação | Result |
---|---|
x < y |
true se x for inferior a y , false caso contrário |
x > y |
true se x for maior que y , false caso contrário |
x <= y |
true se x for menor ou igual a y , false caso contrário |
x >= y |
true se x for maior ou igual a y , false caso contrário |
Por exemplo:
0 <= 1 // true
null < 1 // null
null <= null // null
"ab" < "abc" // true
#nan >= #nan // false
#nan <= #nan // false
O seguinte vale ao avaliar uma expressão que contém os operadores relacionais:
Os erros gerados ao avaliar as expressões ou
x
operandoy
são propagados.Os valores produzidos pela avaliação das
x
expressões ey
devem ser um valor binário, date, datetime, datetimezone, duration, logical, number, null, text ou time. Caso contrário, um erro com o código"Expression.Error"
de razão é gerado.Ambos os operandos devem ser do mesmo tipo de valor ou
null
. Caso contrário, um erro com o código"Expression.Error"
de razão é gerado.Se um ou ambos os operandos forem
null
, o resultado será onull
valor.Dois binários são comparados byte por byte.
Duas datas são comparadas comparando as partes do ano e, se iguais, as partes do mês e, se iguais, as partes do dia.
Duas datas-tempos são comparadas comparando as suas partes do ano e, se iguais, as partes do mês e, se iguais, as partes do dia e, se iguais, as partes da hora e, se iguais, as partes minúsculas e, se iguais, as segundas partes.
Dois fusos datetime são comparados normalizando-os para UTC subtraindo seu deslocamento hora/minuto e, em seguida, comparando seus componentes datetime.
Duas durações são comparadas de acordo com o número total de carrapatos de 100 nanossegundos que representam.
Duas lógicas são comparadas de tal forma que é considerado maior do
true
quefalse
.Dois números
x
ey
são comparados de acordo com as regras do padrão IEEE 754:Se qualquer um dos operandos for
#nan
, o resultado seráfalse
para todos os operadores relacionais.Quando nenhum dos operandos é
#nan
, os operadores comparam os valores dos dois operandos de ponto flutuante em relação à ordenação-∞ < -max < ... < -min < -0.0 = +0.0 < +min < ... < +max < +∞
, onde min e max são os menores e maiores valores finitos positivos que podem ser representados. Os nomes M para -∞ e +∞ são-#infinity
e#infinity
.Efeitos notáveis desta ordenação são:
Os zeros negativos e positivos são considerados iguais.
Um
-#infinity
valor é considerado menor do que todos os outros valores numéricos, mas igual a outro-#infinity
.Um
#infinity
valor é considerado maior do que todos os outros valores numéricos, mas igual a outro#infinity
.
Dois textos são comparados usando uma comparação ordinal caractere a caractere, sensível a maiúsculas e minúsculas e insensível à cultura.
Duas vezes são comparadas comparando suas partes de hora e, se iguais, suas partes minúsculas e, se iguais, suas segundas partes.
Operadores lógicos condicionais
Os and
operadores e or
são chamados de operadores lógicos condicionais.
lógica-ou-expressão:
lógica-e-expressão-lógica-e-expressão-lógica-ou-expressãoor
lógica-e-expressão:
é-expressão
é-expressão-lógica-e-expressãoand
O or
operador retorna true
quando pelo menos um de seus operandos é true
. O operando direito é avaliado se e somente se o operando esquerdo não true
for .
O and
operador retorna false
quando pelo menos um de seus operandos é false
. O operando direito é avaliado se e somente se o operando esquerdo não false
for .
As tabelas de verdade para os or
operadores e and
são mostradas abaixo, com o resultado da avaliação da expressão do operando esquerdo no eixo vertical e o resultado da avaliação da expressão do operando direito no eixo horizontal.
and |
true |
false |
null |
error |
---|---|---|---|---|
true |
true |
false |
null |
error |
false |
false |
false |
false |
false |
null |
null |
false |
null |
error |
error |
error |
error |
error |
error |
or |
true |
false |
null |
error |
---|---|---|---|---|
or |
true |
false |
null |
error |
true |
true |
true |
true |
true |
false |
true |
false |
null |
error |
null |
true |
null |
null |
error |
error |
error |
error |
error |
error |
O seguinte vale ao avaliar uma expressão que contém operadores lógicos condicionais:
Os erros gerados ao avaliar as
x
expressões ouy
são propagados.Os operadores lógicos condicionais são definidos sobre os tipos
logical
enull
. Se os valores do operando não forem desses tipos, um erro com o código"Expression.Error"
de motivo será gerado.O resultado é um valor lógico.
Na expressão
x
ouy
, a expressãoy
será avaliada se e somente sex
não avaliar atrue
.Na expressão
x
ey
, a expressãoy
será avaliada se e somente sex
não avaliar afalse
.
As duas últimas propriedades dão aos operadores lógicos condicionais sua qualificação "condicional"; propriedades também referidas como "curto-circuito". Essas propriedades são úteis para escrever predicados compactos protegidos. Por exemplo, as seguintes expressões são equivalentes:
d <> 0 and n/d > 1 if d <> 0 then n/d > 1 else false
Operadores Aritméticos
Os +
operadores , -
*
, e /
são os operadores aritméticos.
expressão-aditiva:
Expressão multiplicativa
expressão-aditiva-multiplicativa-expressão+
expressão-aditiva-multiplicativa-expressão-
Expressão multiplicativa:
metadados- expressão
expressão multiplicativa-expressão*
de metadados
expressão multiplicativa-expressão/
de metadados
Precisão
Os números em M são armazenados usando uma variedade de representações para reter o máximo de informações possível sobre números provenientes de uma variedade de fontes. Os números só são convertidos de uma representação para outra conforme a necessidade dos operadores aplicados a eles. Duas precisões são suportadas em M:
Precisão | Semântica |
---|---|
Precision.Decimal |
Representação decimal de 128 bits com um intervalo de ±1,0 x 10-28 a ±7,9 x 1028 e 28-29 dígitos significativos. |
Precision.Double |
Representação científica utilizando mantissa e expoente; está em conformidade com o padrão aritmético binário de precisão dupla IEEE 754 IEEE 754-2008 de 64 bits. |
As operações aritméticas são realizadas escolhendo uma precisão, convertendo ambos os operandos para essa precisão (se necessário), executando a operação real e, finalmente, retornando um número na precisão escolhida.
Os operadores aritméticos integrados (+
, -
, *
, /
) usam precisão dupla. As funções padrão da biblioteca (Value.Add
, Value.Subtract
, Value.Multiply
, Value.Divide
) podem ser usadas para solicitar essas operações usando um modelo de precisão específico.
Nenhum estouro numérico é possível:
#infinity
ou-#infinity
representam valores de grandezas muito grandes para serem representados.Nenhum subfluxo numérico é possível:
0
e-0
representam valores de grandezas muito pequenas para serem representados.O valor
#nan
especial IEEE 754 (NaN—Not a Number) é usado para cobrir casos aritmicamente inválidos, como uma divisão de zero por zero.A conversão de precisão decimal para dupla é realizada arredondando números decimais para o valor duplo equivalente mais próximo.
A conversão de precisão dupla para decimal é realizada arredondando números duplos para o valor decimal equivalente mais próximo e, se necessário, transbordando para
#infinity
ou-#infinity
valores.
operador de adição
A interpretação do operador de adição (x + y
) depende do tipo de valor das expressões avaliadas x e y, da seguinte forma:
x | S | Result | Interpretação |
---|---|---|---|
type number |
type number |
type number |
Soma numérica |
type number |
null |
null |
|
null |
type number |
null |
|
type duration |
type duration |
type duration |
Soma numérica de grandezas |
type duration |
null |
null |
|
null |
type duration |
null |
|
type
datetime |
type duration |
type
datetime |
Data/hora deslocada por duração |
type duration |
type
datetime |
type
datetime |
|
type
datetime |
null |
null |
|
null |
type
datetime |
null |
Na tabela, type
datetime significa qualquer um dos type date
, type datetime
, type datetimezone
, ou type time
. Ao adicionar uma duração e um valor de algum tipo datetime, o valor resultante é desse mesmo tipo.
Para outras combinações de valores além das listadas na tabela, um erro com o código "Expression.Error"
de motivo é gerado. Cada combinação é abordada nas seções a seguir.
Os erros gerados ao avaliar qualquer operando são propagados.
Soma numérica
A soma de dois números é calculada usando o operador de adição, produzindo um número.
Por exemplo:
1 + 1 // 2
#nan + #infinity // #nan
O operador +
de adição sobre números usa Precisão Dupla, a função Value.Add
de biblioteca padrão pode ser usada para especificar Precisão Decimal. O seguinte vale ao calcular uma soma de números:
A soma em Precisão Dupla é calculada de acordo com as regras de precisão dupla binária de 64 bits IEEE 754 aritmética IEEE 754-2008. A tabela a seguir lista os resultados de todas as combinações possíveis de valores finitos diferentes de zero, zeros, infinidades e NaN's. Na tabela,
x
e são valores finitos diferentes de zero, ey
é o resultado dez
x + y
. Sex
ey
têm a mesma magnitude mas sinais opostos,z
é zero positivo. Sex + y
for muito grande para ser representado no tipo de destino,z
é um infinito com o mesmo sinalx + y
que .+ S +0 0- +∞ -∞ NaN x z x x +∞ -∞ NaN +0 S +0 +0 +∞ -∞ NaN -0 S +0 0- +∞ -∞ NaN +∞ +∞ +∞ +∞ +∞ NaN NaN -∞ -∞ -∞ -∞ NaN -∞ NaN NaN NaN NaN NaN NaN NaN NaN A soma em precisão decimal é calculada sem perder a precisão. A escala do resultado é a maior das escalas dos dois operandos.
Soma das durações
A soma de duas durações é a duração que representa a soma do número de carrapatos de 100 nanossegundos representados pelas durações. Por exemplo:
#duration(2,1,0,15.1) + #duration(0,1,30,45.3)
// #duration(2, 2, 31, 0.4)
Data/hora deslocada por duração
Uma e uma duração x
podem ser adicionadas usando y
para calcular uma nova x + y
cuja distância de uma linha do tempo linear é exatamente a magnitude de x
. Aqui, datetime significa qualquer um dos Date
, DateTime
, DateTimeZone
, ou Time
e um resultado não nulo será do mesmo tipo. O deslocamento datetime por duração pode ser calculado da seguinte forma:
Se o valor datetime days since epoch for especificado, construa um novo datetime com os seguintes elementos de informação:
Calcule um novo dia desde a época equivalente a dividir a magnitude de y pelo número de ticks de 100 nanossegundos em um período de 24 horas, truncando a porção decimal do resultado e adicionando esse valor aos dias de x desde a época.
Calcule um novo ticks desde a meia-noite equivalente a adicionar a magnitude de y aos ticks do x desde a meia-noite, modulo o número de ticks de 100 nanossegundos em um período de 24 horas. Se x não especificar um valor para ticks desde a meia-noite, um valor de 0 será assumido.
Copie o valor de x para minutos deslocados do UTC inalterado.
Se o valor datetime days since epoch não for especificado, construa um novo datetime com os seguintes elementos de informação especificados:
Calcule um novo ticks desde a meia-noite equivalente a adicionar a magnitude de y aos ticks do x desde a meia-noite, modulo o número de ticks de 100 nanossegundos em um período de 24 horas. Se x não especificar um valor para ticks desde a meia-noite, um valor de 0 será assumido.
Copie os valores de x por dias desde a época e minutos deslocados do UTC inalterado.
Os exemplos a seguir mostram o cálculo da soma temporal absoluta quando a datetime especifica os dias desde a época:
#date(2010,05,20) + #duration(0,8,0,0)
//#datetime( 2010, 5, 20, 8, 0, 0 )
//2010-05-20T08:00:00
#date(2010,01,31) + #duration(30,08,0,0)
//#datetime(2010, 3, 2, 8, 0, 0)
//2010-03-02T08:00:00
#datetime(2010,05,20,12,00,00,-08) + #duration(0,04,30,00)
//#datetime(2010, 5, 20, 16, 30, 0, -8, 0)
//2010-05-20T16:30:00-08:00
#datetime(2010,10,10,0,0,0,0) + #duration(1,0,0,0)
//#datetime(2010, 10, 11, 0, 0, 0, 0, 0)
//2010-10-11T00:00:00+00:00
O exemplo a seguir mostra o cálculo do deslocamento datetime por duração para um determinado tempo:
#time(8,0,0) + #duration(30,5,0,0)
//#time(13, 0, 0)
//13:00:00
operador de subtração
A interpretação do operador de subtração (x - y
) depende do tipo de valor das expressões x
avaliadas e y
, da seguinte forma:
x | Y | Result | Interpretação |
---|---|---|---|
type number |
type number |
type number |
Diferença numérica |
type number |
null |
null |
|
null |
type number |
null |
|
type duration |
type duration |
type duration |
Diferença numérica de magnitudes |
type duration |
null |
null |
|
null |
type duration |
null |
|
type
datetime |
type
datetime |
type duration |
Duração entre datetimes |
type
datetime |
type duration |
type
datetime |
Data/hora compensada pela duração negada |
type
datetime |
null |
null |
|
null |
type
datetime |
null |
Na tabela, type
datetime significa qualquer um dos type date
, type datetime
, type datetimezone
, ou type time
. Ao subtrair uma duração de um valor de algum tipo datetime, o valor resultante é desse mesmo tipo.
Para outras combinações de valores além das listadas na tabela, um erro com o código "Expression.Error"
de motivo é gerado. Cada combinação é abordada nas seções a seguir.
Os erros gerados ao avaliar qualquer operando são propagados.
Diferença numérica
A diferença entre dois números é calculada usando o operador de subtração, produzindo um número. Por exemplo:
1 - 1 // 0
#nan - #infinity // #nan
O operador -
de subtração sobre números usa Precisão Dupla, a função Value.Subtract
de biblioteca padrão pode ser usada para especificar Precisão Decimal. O seguinte vale ao calcular uma diferença de números:
A diferença na Precisão Dupla é calculada de acordo com as regras da aritmética IEEE 754-2008 IEEE 754-2008 de precisão dupla binária de 64 bits. A tabela a seguir lista os resultados de todas as combinações possíveis de valores finitos diferentes de zero, zeros, infinidades e NaN's. Na tabela,
x
e são valores finitos diferentes de zero, ey
é o resultado dez
x - y
. Sex
ey
são iguais,z
é zero positivo. Sex - y
for muito grande para ser representado no tipo de destino,z
é um infinito com o mesmo sinalx - y
que .- S +0 0- +∞ -∞ NaN x z x x -∞ +∞ NaN +0 -y +0 +0 -∞ +∞ NaN -0 -y 0- +0 -∞ +∞ NaN +∞ +∞ +∞ +∞ NaN +∞ NaN -∞ -∞ -∞ -∞ -∞ NaN NaN NaN NaN NaN NaN NaN NaN NaN A diferença na precisão decimal é calculada sem perder a precisão. A escala do resultado é a maior das escalas dos dois operandos.
Diferença de durações
A diferença de duas durações é a duração que representa a diferença entre o número de ticks de 100 nanossegundos representados por cada duração. Por exemplo:
#duration(1,2,30,0) - #duration(0,0,0,30.45)
// #duration(1, 2, 29, 29.55)
Data/hora compensada pela duração negada
Uma data/horax
e uma duração y
podem ser subtraídas usando x - y
para calcular uma nova data/hora. Aqui, datetime significa qualquer um dos date
, datetime
, datetimezone
, ou time
. O datetime resultante . Subtrair durações positivas produz resultados que estão atrasados no tempo em relação ao , enquanto subtrair x
valores negativos produz resultados que são avançados no tempo.
#date(2010,05,20) - #duration(00,08,00,00)
//#datetime(2010, 5, 19, 16, 0, 0)
//2010-05-19T16:00:00
#date(2010,01,31) - #duration( 30,08,00,00)
//#datetime(2009, 12, 31, 16, 0, 0)
//2009-12-31T16:00:00
Duração entre duas datas/hora
Duas datas/horat
e u
podem ser subtraídas usando t - u
para calcular a duração entre elas. Aqui, datetime significa qualquer um dos date
, datetime
, datetimezone
, ou time
. A duração produzida por subtração u
do mosto produz t
quando adicionada t
a u
.
#date(2010,01,31) - #date(2010,01,15)
// #duration(16,00,00,00)
// 16.00:00:00
#date(2010,01,15)- #date(2010,01,31)
// #duration(-16,00,00,00)
// -16.00:00:00
#datetime(2010,05,20,16,06,00,-08,00) -
#datetime(2008,12,15,04,19,19,03,00)
// #duration(521,22,46,41)
// 521.22:46:41
Subtrair t - u
quando u > t
resulta numa duração negativa:
#time(01,30,00) - #time(08,00,00)
// #duration(0, -6, -30, 0)
O seguinte vale ao subtrair duas datetimes usando t - u
:
- u + (t - u) = t
operador de multiplicação
A interpretação do operador de multiplicação (x * y
) depende do tipo de valor das expressões avaliadas x e y, da seguinte forma:
X | Y | Result | Interpretação |
---|---|---|---|
type number |
type number |
type number |
Produto numérico |
type number |
null |
null |
|
null |
type number |
null |
|
type duration |
type number |
type duration |
Múltiplos de duração |
type number |
type duration |
type duration |
Múltiplos de duração |
type duration |
null |
null |
|
null |
type duration |
null |
Para outras combinações de valores além das listadas na tabela, um erro com o código "Expression.Error"
de motivo é gerado. Cada combinação é abordada nas seções a seguir.
Os erros gerados ao avaliar qualquer operando são propagados.
Produto numérico
O produto de dois números é calculado usando o operador de multiplicação, produzindo um número. Por exemplo:
2 * 4 // 8
6 * null // null
#nan * #infinity // #nan
O operador *
de multiplicação sobre números usa Precisão Dupla, a função Value.Multiply
de biblioteca padrão pode ser usada para especificar Precisão Decimal. O seguinte vale ao calcular um produto de números:
O produto em Double Precision é calculado de acordo com as regras de 64-bit binário de dupla precisão IEEE 754 aritmética IEEE 754-2008. A tabela a seguir lista os resultados de todas as combinações possíveis de valores finitos diferentes de zero, zeros, infinidades e NaN's. Na tabela,
x
ey
são valores finitos positivos.z
é o resultado dex * y
. Se o resultado for muito grande para o tipo de destino,z
é infinito. Se o resultado for muito pequeno para o tipo de destino,z
é zero.* +y -y +0 0- +∞ -∞ NaN +x +z -z +0 0- +∞ -∞ NaN -x -z +z 0- +0 -∞ +∞ NaN +0 +0 0- +0 0- NaN NaN NaN -0 0- +0 0- +0 NaN NaN NaN +∞ +∞ -∞ NaN NaN +∞ -∞ NaN -∞ -∞ +∞ NaN NaN -∞ +∞ NaN NaN NaN NaN NaN NaN NaN NaN NaN O produto em Precisão Decimal é calculado sem perder a precisão. A escala do resultado é a maior das escalas dos dois operandos.
Múltiplos de durações
O produto de uma duração e um número é a duração que representa o número de ticks de 100nanossegundos representado pelo operando de duração vezes o operando de número. Por exemplo:
#duration(2,1,0,15.1) * 2
// #duration(4, 2, 0, 30.2)
operador de divisão
A interpretação do operador de divisão (x / y
) depende do tipo de valor das expressões x
avaliadas e y
, da seguinte forma:
X | Y | Result | Interpretação |
---|---|---|---|
type number |
type number |
type number |
Quociente numérico |
type number |
null |
null |
|
null |
type number |
null |
|
type duration |
type number |
type duration |
Fração de duração |
type duration |
type duration |
type number |
Quociente numérico de durações |
type duration |
null |
null |
|
null |
type duration |
null |
Para outras combinações de valores além das listadas na tabela, um erro com o código "Expression.Error"
de motivo é gerado. Cada combinação é abordada nas seções a seguir.
Os erros gerados ao avaliar qualquer operando são propagados.
Quociente numérico
O quociente de dois números é calculado usando o operador de divisão, produzindo um número. Por exemplo:
8 / 2 // 4
8 / 0 // #infinity
0 / 0 // #nan
0 / null // null
#nan / #infinity // #nan
O operador /
de divisão sobre números usa Precisão Dupla, a função Value.Divide
de biblioteca padrão pode ser usada para especificar Precisão Decimal. O seguinte vale ao calcular um quociente de números:
O quociente em Precisão Dupla é calculado de acordo com as regras de precisão dupla binária de 64 bits IEEE 754 aritmética IEEE 754-2008. A tabela a seguir lista os resultados de todas as combinações possíveis de valores finitos diferentes de zero, zeros, infinidades e NaN's. Na tabela,
x
ey
são valores finitos positivos.z
é o resultado dex / y
. Se o resultado for muito grande para o tipo de destino,z
é infinito. Se o resultado for muito pequeno para o tipo de destino,z
é zero./ +y -y +0 0- +∞ -∞ NaN +x +z -z +∞ -∞ +0 0- NaN -x -z +z -∞ +∞ 0- +0 NaN +0 +0 0- NaN NaN +0 0- NaN -0 0- +0 NaN NaN 0- +0 NaN +∞ +∞ -∞ +∞ -∞ NaN NaN NaN -∞ -∞ +∞ -∞ +∞ NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN A soma em precisão decimal é calculada sem perder a precisão. A escala do resultado é a maior das escalas dos dois operandos.
Quociente de durações
O quociente de duas durações é o número que representa o quociente do número de ticks de 100nanossegundos representado pelas durações. Por exemplo:
#duration(2,0,0,0) / #duration(0,1,30,0)
// 32
Durações dimensionadas
O quociente de uma duração x
e um número y
é a duração que representa o quociente do número de carrapatos de 100 nanossegundos representado pela duração x
e pelo número y
. Por exemplo:
#duration(2,0,0,0) / 32
// #duration(0,1,30,0)
Combinação de estruturas
O operador de combinação (x & y
) é definido sobre os seguintes tipos de valores:
X | Y | Result | Interpretação |
---|---|---|---|
type text |
type text |
type text |
Concatenação |
type text |
null |
null |
|
null |
type text |
null |
|
type date |
type time |
type datetime |
Unir |
type date |
null |
null |
|
null |
type time |
null |
|
type list |
type list |
type list |
Concatenação |
type record |
type record |
type record |
Unir |
type table |
type table |
type table |
Concatenação |
Concatenação
Dois valores de texto, duas listas ou duas tabelas podem ser concatenados usando x & y
.
O exemplo a seguir ilustra a concatenação de valores de texto:
"AB" & "CDE" // "ABCDE"
O exemplo a seguir ilustra listas concatenadoras:
{1, 2} & {3} // {1, 2, 3}
O seguinte vale ao concatenar dois valores usando x & y
:
Os erros gerados ao avaliar as
x
expressões ouy
são propagados.Nenhum erro é propagado se um item de um ou
x
y
contém um erro.O resultado da concatenação de dois valores de texto é um valor de texto que contém o valor de x imediatamente seguido por y. Se um dos operandos for nulo e o outro for um valor de texto, o resultado será nulo.
O resultado da concatenação de duas listas é uma lista que contém todos os itens de
x
seguido por todos os itens dey
.O resultado da concatenação de duas tabelas é uma tabela que tem a união das duas colunas da tabela de operando. A ordenação das colunas é
x
preservada, seguida pelas colunas que aparecem apenas emy
, preservando a sua ordem relativa. Para colunas que aparecem apenas em um dos operandos,null
é usado para preencher valores de célula para o outro operando.
Unir
Mesclagem de registros
Dois registros podem ser mesclados usando x & y
, produzindo um registro que inclui campos de ambos e x
y
.
Os exemplos a seguir ilustram a fusão de registros:
[ x = 1 ] & [ y = 2 ] // [ x = 1, y = 2 ]
[ x = 1, y = 2 ] & [ x = 3, z = 4 ] // [ x = 3, y = 2, z = 4 ]
O seguinte é válido ao mesclar dois registros usando x + y
:
Os erros gerados ao avaliar as
x
expressões ouy
são propagados.Se um campo aparecer em ambos
x
ey
, o valor dey
é usado.A ordem dos campos no registro resultante é a de , seguida pelos
x
campos emy
que não fazem parte dex
, na mesma ordem em que aparecem emy
.A fusão de registros não causa avaliação dos valores.
Nenhum erro é gerado porque um campo contém um erro.
O resultado é um recorde.
Mesclagem data-hora
Uma data x
pode ser mesclada com uma hora y
usando x & y
, produzindo uma data/hora que combina as partes de ambos e x
y
.
O exemplo a seguir ilustra a fusão de uma data e uma hora:
#date(2013,02,26) & #time(09,17,00)
// #datetime(2013,02,26,09,17,00)
O seguinte é válido ao mesclar dois registros usando x + y
:
Os erros gerados ao avaliar as
x
expressões ouy
são propagados.O resultado é uma data/hora.
Operadores unários
O +
, -
e not
operadores são operadores unários.
unário-expressão:
tipo-expressão
+
Expressão unária
-
Expressão unária
not
Expressão unária
Unary plus operador
O operador unary plus (+x
) é definido para os seguintes tipos de valores:
X | Result | Interpretação |
---|---|---|
type number |
type number |
Unário mais |
type duration |
type duration |
Unário mais |
null |
«Nulo |
Para outros valores, um erro com código "Expression.Error"
de motivo é gerado.
O operador unary plus permite que um +
sinal seja aplicado a um número, datetime ou valor nulo. O resultado é esse mesmo valor. Por exemplo:
+ - 1 // -1
+ + 1 // 1
+ #nan // #nan
+ #duration(0,1,30,0) // #duration(0,1,30,0)
Ao avaliar o operador +x
unary plus, é válido o seguinte:
Os erros gerados durante a avaliação
x
são propagados.Se o resultado da avaliação
x
não for um valor numérico, um erro com o código"Expression.Error"
de razão será gerado.
Unary menos operador
O operador unário menos (-x
) é definido para os seguintes tipos de valores:
X | Result | Interpretação |
---|---|---|
type number |
type number |
Negação |
type duration |
type duration |
Negação |
null |
null |
Para outros valores, um erro com código "Expression.Error"
de motivo é gerado.
O operador unário menos é usado para alterar o sinal de um número ou duração. Por exemplo:
- (1 + 1) // -2
- - 1 // 1
- - - 1 // -1
- #nan // #nan
- #infinity // -#infinity
- #duration(1,0,0,0) // #duration(-1,0,0,0)
- #duration(0,1,30,0) // #duration(0,-1,-30,0)
Ao avaliar o operador -x
unário menos :
Os erros gerados durante a avaliação
x
são propagados.Se a expressão for um número, o resultado será o valor numérico da expressão
x
com seu sinal alterado. Se o valor for NaN, então o resultado também é NaN.
Operador de negação lógica
O operador de negação lógica (not
) é definido para os seguintes tipos de valores:
X | Result | Interpretação |
---|---|---|
type logical |
type logical |
Negação |
null |
null |
Este operador calcula a operação lógica not
em um determinado valor lógico. Por exemplo:
not true // false
not false // true
not (true and true) // false
O seguinte vale ao avaliar o operador not x
de negação lógica:
Os erros gerados durante a avaliação
x
são propagados.O valor produzido a partir da avaliação da expressão x deve ser um valor lógico ou um erro com o código
"Expression.Error"
de razão deve ser gerado. Se o valor fortrue
, o resultado seráfalse
. Se o operando forfalse
, o resultado serátrue
.
O resultado é um valor lógico.
Operadores de tipo
Os operadores is
e as
são conhecidos como os operadores de tipo.
Operador de compatibilidade de tipo
O operador x is y
de compatibilidade de tipo é definido para os seguintes tipos de valores:
X | Y | Result |
---|---|---|
type any |
nullable-primitive-type | type logical |
A expressão x is y
retorna true
se o tipo atribuído de x
é compatível com y
, e retorna false
se o tipo atribuído de x
é incompatível com y
.
y
deve ser um tipo primitivo nulo.
é-expressão:
como-expressão
is-expressionis
nullable-primitive-type
nullable-primitive-type:
nullable
opt primitivo-tipo
A compatibilidade de tipo, conforme suportado is
pelo operador, é um subconjunto da compatibilidade geral de tipo e é definida usando as seguintes regras:
Se
x
é nulo, então é compatível sey
é o tipoany
, o tiponull
, ou um tipo anulável.Se
x
é não-nulo, então se é um compatível, se o tipo primitivo dex
é o mesmo quey
.
Ao avaliar a expressão x is y
, é válido o seguinte:
- Um erro gerado ao avaliar a expressão
x
é propagado.
Operador de asserção de tipo
O operador x as y
de asserção de tipo é definido para os seguintes tipos de valores:
X | Y | Result |
---|---|---|
type any |
nullable-primitive-type | type any |
A expressão x as y
afirma que o valor x
é compatível com o operador de acordo com y
o is
operador. Se não for compatível, um erro é gerado.
y
deve ser um tipo primitivo anulável.
Como expressão:
igualdade-expressão
as-expressionas
nullable-primitive-type
A expressão x as y
é avaliada da seguinte forma:
Uma verificação
x is y
de compatibilidade de tipo é executada e a asserção retornax
inalterada se o teste for bem-sucedido.Se a verificação de compatibilidade falhar, um erro com o código
"Expression.Error"
de motivo será gerado.
Exemplos:
1 as number // 1
"A" as number // error
null as nullable number // null
Ao avaliar a expressão x as y
, é válido o seguinte:
- Um erro gerado ao avaliar a expressão
x
é propagado.
Operador de coalesce
O operador ??
coalesce retorna o resultado de seu operando esquerdo se ele não for nulo, caso contrário, ele retornará o resultado de seu operando direito. O operando direito é avaliado se e somente se o operando esquerdo for nulo.