Operadores



Operadores Infix

Os operadores Infix pegam dois operandos e são escritos entre esses operandos. Os operadores aritméticos e de comparação são os mais comuns:

1 + 2
a < b

O Pony tem praticamente o mesmo conjunto de operadores infix que outras linguagens.

Operadores de Analise

A maioria dos operadores infix no Pony são na verdade pseudônimos para funções. O operando esquerdo é o receptor, a função é chamada e o operando direito é passado como um argumento. Por exemplo, as seguintes expressões são equivalentes:

x + y
x.add(y)

Isto significa que + não é um símbolo especial que só pode ser aplicado a tipos mágicos. Qualquer tipo pode fornecer sua própria função de adição e o programador pode então usar + com esse tipo se assim o desejar.

Ao definir sua própria função de adição, não há restrição quanto aos tipos do parâmetro ou do tipo de retorno. O lado direito do + terá que combinar com o tipo de parâmetro e a expressão inteira + terá o tipo que adiciona retornos.

Aqui está um exemplo completo para definir um tipo que permite o uso do +. Isto é tudo o que você precisa:

// Define a suitable type
class Pair
var _x: U32 = 0
var _y: U32 = 0
new create(x: U32, y: U32) =>
_x = x
_y = y
// Define a + function
fun add(other: Pair): Pair =>
Pair(_x + other._x, _y + other._y)
// Now let's use it
class Foo
fun foo() =>
var x = Pair(1, 2)
var y = Pair(3, 4)
var z = x + y

É possível sobrecarregar os operadores infix até certo ponto usando tipos de união ou polimorfismo f-bounded, mas isto está além do escopo deste tutorial. Consulte a biblioteca padrão do Pony para maiores informações.

Você não precisa se preocupar com nada disso se não quiser. Você pode simplesmente usar os operadores infix existentes para números como qualquer outro idioma e não fornecê-los para seus próprios tipos.

A lista completa dos operadores infix que são pseudônimos para funções é:

Operador Metodo Descrição Notas
+ add() Adição
- sub() Subtração
* mul() Multiplicação
/ div() Divisão
% rem() Resto
%% mod() Modulo A partir da versão 0.26.1
<< shl() Mover um bit a esquerda
>> shr() Mover um bit a direita
and op_and() And, bit a bit e lógico
or op_or() Or, bit a bit e lógico
xor op_xor() Xor, bit a bit e lógico
== eq() Igualdade
!= ne() Não-igualdade
< lt() Menor que
<= le() Menor ou igual que
>= ge() Maior ou igual que
>> gt() Maior que
>~ gt_unsafe() Maior que (inseguro)
+~ add_unsafe() Adição (inseguro)
-~ sub_unsafe() Subtração (inseguro)
*~ mul_unsafe() Multiplicação (inseguro)
/~ div_unsafe() Divisão (inseguro)
%~ rem_unsafe() Resto (inseguro)
%%~ mod_unsafe() Modulo(inseguro) A partir da versão 0.26.1
<<~ shl_unsafe() Mover um bit a esquerda (inseguro)
>>~ shr_unsafe() Mover um bit a direita (inseguro)
==~ eq_unsafe() Igualdade (inseguro)
!=~ ne_unsafe() Não-igualdade (inseguro)
<~ lt_unsafe() Menor que (inseguro)
<=~ le_unsafe() Menor ou igual que (inseguro)
>=~ ge_unsafe() Maior ou igual que (inseguro)
+? add_partial()? Adição parcial
-? sub_partial()? Subtração parcial
*? mul_partial()? Multiplicação parcial
/? div_partial()? Divisão parcial
%? rem_partial()? Resto parcial
%%? mod_partial()? Modulo parcial A partir da versão 0.26.1

Curto-circuito

Os operadores and/or usam curto-circuito quando usados com variáveis Bool. Isto significa que o primeiro operando é sempre avaliado, mas o segundo só é avaliado se puder afetar o resultado.

Para and, se o primeiro operando for falso, então o segundo operando não é avaliado uma vez que não pode afetar o resultado.

Para or, se o primeiro operando for verdadeiro, então o segundo operando não é avaliado uma vez que não pode afetar o resultado.

Esta é uma característica especial embutida no compilador, não pode ser usada com o apelido de operador para qualquer outro tipo.

Operadores unários

Os operadores unários são tratados da mesma maneira, mas com apenas um operando. Por exemplo, as seguintes expressões são equivalentes:

-x
x.neg()

A lista completa de operadores unários que são pseudônimos para funções é:

Operador Metodo Descrição
- neg() Negação aritmética
not op_not() Not, bit a bit e lógico
-~ neg_unsafe() Negação aritmética (inseguro)

Precedência

No Pony, os operadores unários sempre se unem mais fortes do que qualquer operador infix: not a == b será interpretado como (not a) == b ao invés de not (a == b).

Ao utilizar operadores infix em expressões complexas, uma questão-chave é a precedência, ou seja, qual operador é avaliado primeiro. Dada esta expressão:

1 + 2 * 3 // Compilation failed.

Obteremos um valor de 9 se avaliarmos primeiro a adição e 7 se avaliarmos primeiro a multiplicação. Em matemática, existem regras sobre a ordem em que se avaliam os operadores e a maioria das linguagens de programação seguem esta abordagem.

O problema com isto é que o programador tem que se lembrar da ordem e as pessoas não são muito boas em coisas como esta. A maioria das pessoas se lembrará de fazer multiplicação antes da adição, mas e quanto à mudança do bit esquerdo em relação ao and bit a bit? Às vezes as pessoas se lembram mal (ou adivinham errado) e isso leva a bugs. Pior ainda, esses bugs são muitas vezes muito difíceis de serem identificados.

O Pony tem uma abordagem diferente e os foras-da-lei têm precedência infixada. Qualquer expressão onde mais de um operador infix é usado deve usar parênteses para remover a ambigüidade. Se você não fizer isso, o compilador irá reclamar.

Isto significa que o exemplo acima é ilegal no Pony e deve ser reescrito como:

1 + (2 * 3) // 7

O uso repetido de um único operador, entretanto, é permitido:

1 + 2 + 3 // 6

Enquanto isso, a mistura de operadores unários e infix não precisa de parênteses adicionais, pois os operadores unários sempre se unem mais estreitamente, portanto, se nosso exemplo acima usou um três negativo:

1 + 2 * -3 // Compilation failed.

Ainda precisaríamos de parênteses para remover a ambigüidade para nossos operadores infix como fizemos acima, mas não para o negativo aritmético unário (-):

1 + (2 * -3) // -5

Podemos ver que faz mais sentido que o operador unário seja aplicado antes do infix, já que ele só atua sobre um único número na expressão, portanto nunca é ambíguo.

Os operadores unários também podem ser aplicados a parênteses e agir sobre o resultado de todas as operações nesses parênteses antes de aplicar qualquer operador infix fora dos parênteses:

1 + -(2 * -3) //