> For the complete documentation index, see [llms.txt](https://gabriel-schade-cardoso.gitbook.io/tango-br/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gabriel-schade-cardoso.gitbook.io/tango-br/tipos/introduction-2.md).

# Either\<TLeft, TRight>

> [`Tango.Types.Either<TLeft, TRight>`](https://github.com/gabrielschade/Tango/blob/master/Tango/Tango/Types/Either.cs)

Esta classe representa valores "ou um ou outro".

Instâncias de `Either<TLeft, TRight>` encapsulam um valor que pode pertencer a um dos dois possíveis tipos: `TLeft` ou `TRight`. Este valor só pode ser acessado através dos métodos `Match` e `Match2`.

Uma utilização comum deste tipo é uma alternativa ao tipo `Option<T>` para lidar com possíveis erros, mas neste caso o estado "Não contendo nada" é substituído por um valor de um tipo diferente.

Por convenção o tipo `TLeft` representa o tipo problemático enquanto o `TRight` representa o tipo resultante no caminho feliz.

Os valores either possuem dois estados:

* Esquerda (`IsLeft`) - Quando contém um valor do tipo `TLeft`;
* Direita (`IsRight`) - Quando contém um valor do tipo `TRight`.

## Propriedades

| Nome    | Tipo | Descrição                                                                         |
| ------- | ---- | --------------------------------------------------------------------------------- |
| IsLeft  | bool | Retorna true quando o valor contido no tipo either é do tipo definido por TLeft.  |
| IsRight | bool | Retorna true quando o valor contido no tipo either é do tipo definido por TRight. |

## Construtores

| Parâmetros   | Retorno                | Descrição                                                                                                          |
| ------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------ |
| TLeft left   | Either\<TLeft, TRight> | Inicializa uma nova instância de um valor Either com o estado IsLeft encapsulando o valor informado no parâmetro.  |
| TRight right | Either\<TLeft, TRight> | Inicializa uma nova instância de um valor Either com o estado IsRight encapsulando o valor informado no parâmetro. |

## Métodos

| Nome   | Parâmetros                                                                                                                                                                                                                                         | Retorno | Descrição                                                                                                                                                                                                                                                                                                                                                                               |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Match  | <p>Func\<TRight,TResult> methodWhenRight</p><p>Func\<TLeft, TResult> methodWhenLeft</p>                                                                                                                                                            | TResult | <p>Permite uma maneira de aplicar um método à um valor either sem necessidade de checar o estado do valor.</p><p>Para isso são passados dois métodos por parâmetro. Estes métodos precisam retornar o mesmo tipo e cada um deles deve esperar um parâmetro diferente, dos tipos TLeft e TRight. Eles serão chamados de acordo com o estado do valor Either (IsLeft ou IsRight).</p>     |
| Match2 | <p>Either\<TLeft2, TRight2> either2</p><p>Func\<TRight, TRight2, T> methodWhenBothRight</p><p>Func\<TRight, TLeft2, T> methodWhenRightLeft</p><p>Func\<TLeft, TRight2, T> methodWhenLeftRight</p><p>Func\<TLeft, TLeft2, T> methodWhenBothLeft</p> | T       | <p>Permite uma maneira de aplicar um método à dois valores either sem necessidade de checar os estados de cada valor.</p><p>Para isso são passados quatro métodos contendo o mesmo tipo de retorno por parâmetro, onde cada um deles será chamado de acordo com o estado dos dois valores either.</p>                                                                                   |
| Match  | <p>Action\<TRight> methodWhenRight</p><p>Action\<TLeft> methodWhenLeft</p>                                                                                                                                                                         | Unit    | <p>Permite uma maneira de aplicar um método à um valor either sem necessidade de checar o estado do valor.</p><p>Para isso são passados dois métodos por parâmetro. Estes métodos precisam não conter retorno (void) e cada um deles deve esperar um parâmetro diferente, dos tipos TLeft e TRight. Eles serão chamados de acordo com o estado do valor Either (IsLeft ou IsRight).</p> |
| Match2 | <p>Either\<TLeft2, TRight2> either2</p><p>Action\<TRight, TRight2> methodWhenBothRight</p><p>Action\<TRight, TLeft2> methodWhenRightLeft</p><p>Action\<TLeft, TRight2> methodWhenLeftRight</p><p>Action\<TLeft, TLeft2> methodWhenBothLeft</p>     | T       | <p>Permite uma maneira de aplicar um método à dois valores either sem necessidade de checar os estados de cada valor.</p><p>Para isso são passados quatro métodos por parâmetro, onde eles precisam não retornar nenhum valor (void) e cada um será chamado de acordo com o estado dos dois valores either.</p>                                                                         |

## Sobrecargas de operadores

| Operador       | Parâmetros                   | Retorno                | Descrição                                                                                                                                                                                                                                                   |
| -------------- | ---------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Cast implícito | TLeft left                   | Either\<TLeft, TRight> | Permite a criação de um valor Either através de um cast implícito de qualquer valor TLeft para seu respectivo valor Either.                                                                                                                                 |
| Cast implícito | TRight right                 | Either\<TLeft, TRight> | Permite a criação de um valor Either através de um cast implícito de qualquer valor TRight para seu respectivo valor Either.                                                                                                                                |
| Cast implícito | Either\<TLeft, TRight>       | Option\<TLeft>         | <p>Permite a criação de um valor Option\<TLeft> através de um cast implícito de um valor Either.</p><p>Caso o valor Either esteja no estado IsRight será criado um valor opcional no estado IsNone.</p>                                                     |
| Cast implícito | Either\<TLeft, TRight>       | Option\<TRight>        | <p>Permite a criação de um valor Option\<TRight> através de um cast implícito de um valor Either.</p><p>Caso o valor Either esteja no estado IsLeft será criado um valor opcional no estado IsNone.</p>                                                     |
| Cast implícito | Continuation\<TLeft, TRight> | Either\<TLeft, TRight> | <p>Permite a criação de um valor Either\<TLeft, TRight> através de um cast implícito de um valor Continuation.</p><p>Caso o valor Continuation esteja no estado IsFail será criado um valor Either no estado IsLeft, caso contrário, no estado IsRight.</p> |

## Como Usar

Você pode criar um valor either de várias formas diferentes, inclusive para atribuir mais informações à um valor `Option<T>`.

### Criando valores Either

Você pode utilizar o construtor para criar valores contendo o estado `IsLeft` ou `IsRight` de acordo com o parâmetro, conforme código:

**Utilizando o construtor**

```csharp
Either<bool, int> valueWithRight = new Either<bool, int>(10); //-> IsRight
Either<bool, int> valueWithLeft = new Either<bool, int>(false); //-> IsLeft
```

Devido às sobrecargas de cast implícito você não precisa se preocupar com nenhum tipo de sintaxe e nem utilizar o construtor, basta criar o valor de um dos dois tipos `TLeft` ou `TRight` declarado e a linguagem fará todo o trabalho.

&#x20;**Utilizando cast implícito**

```csharp
Either<bool, int> valueWithRight = 10;   //-> IsRight
Either<bool, int> valueWithLeft = false; //-> IsLeft
```

Através deste cast implícito, você poderá gerar novos métodos para retornar o tipo Either em sua aplicação sem alterar nada no corpo especial da função, apenas indicando que a função retorna um valor Either e informando duas instruções de return com tipos **diferentes**.

Veja este exemplo:

```csharp
private Either<string, int> GetSquareIfEven(int value)
{
  if (value % 2 == 0)
    return value * value;
  else
    return "Odd";
}
```

Pode parecer estranho ter duas instruções de retorno com valores de tipos diferentes, mas na verdade ambos retornam um valor do tipo `Either`, mas estamos deixando esta responsabilidade com o C#.

### Obtendo informação de um valor Either

Assim como nos valores opcionais é necessário utilizar os métodos `Match` ou `Match2` para obter a informação de um valor Either, no entanto, existe a possibilidade de extrair a informação de um valor Either realizando um cast implícito para um valor opcional.

Neste caso o valor opcional terá que identificar um dos dois tipos `TLeft` ou `TRight`. Caso o tipo identificado pelo `Option` seja o tipo referente ao estado atual do valor `Either` será gerado um valor opcional no estado `IsSome`, caso contrário será gerado no estado `IsNone`.

Com isso, é necessário tratar adequadamente todas as possibilidades para obter um valor de um `Either`.

&#x20;**Utilizando o cast implícito para Option**&#x20;

```csharp
Either<bool, int> eitherValue = 10;
Option<int> optionValue = eitherValue;

//optionValue.IsSome = true
```

```csharp
Either<bool, int> eitherValue = 10;
Option<bool> optionValue = eitherValue;

//optionValue.IsSome = false
//optionValue.IsNone = true
```

> &#x20;**Atenção**&#x20;
>
> Mesmo realizando o cast implícito para o tipo correto, podem haver casos onde o valor opcional esteja no estado IsNone.
>
> Esta situação ocorre quando o valor armazenado no tipo Either é igual ao valor `default` ou igual à `null`.

```csharp
Either<bool, int> eitherValue = 0;
Option<int> optionValue = eitherValue;

//optionValue.IsSome = false
//optionValue.IsNone = true
```

Os métodos `Match` esperam dois métodos por parâmetro, estes métodos podem realizar transformações no valor Either, ou apenas retorná-los, conforme exemplos:

&#x20;**Utilizando Match com parâmetros nomeados**

```csharp
Either<bool, int> eitherValue = 10;
int value = eitherValue.Match(
        methodWhenRight: number => number,
        methodWhenLeft: boolean => 0);

//value = 10
```

O primeiro método será executado apenas se o valor either estiver no estado `IsRight`, logo, este método recebe um valor do tipo à direita por parâmetro, `int`, no exemplo.

O segundo método recebe um valor do tipo à esquerda, `bool`, mas note que ambos precisam retornar valores do mesmo tipo. Portanto, foi utilizado o valor zero (0) para seguir o fluxo da aplicação caso o Either esteja no estado `IsLeft`.

Não há necessidade de nomear os métodos, basta utilizá-los na ordem correta.

&#x20;**Utilizando Match**&#x20;

```csharp
Either<bool, int> eitherValue = 10;
int value = eitherValue.Match(
        number => number,
        boolean => 0);

//value = 10
```

Além disso, você também pode aplicar algum tipo de transformação no valor no momento de obtê-lo, como por exemplo, elevá-lo ao quadrado.

```csharp
Either<bool, int> eitherValue = 10;
int value = eitherValue.Match(
        number => number * number,
        boolean => 0);

//value = 100
```

Você também pode retornar o valor que precisar para o caso do estado ser `IsLeft`, nos exemplos anteriores foi utilizado o valor zero, mas não há nenhuma obrigatoriedade nisso.

O método Match também não precisa retornar nenhum dos dois tipos do valor Either.

&#x20;**Utilizando Match para retornar um novo valor**&#x20;

```csharp
Either<bool, int> eitherValue = 10;
string value = eitherValue.Match(
        number => number.ToString(),
        boolean => boolean.ToString());

//value = "10"
```

```csharp
Either<bool, int> eitherValue = false;
string value = eitherValue.Match(
        number => number.ToString(),
        boolean => boolean.ToString());

//value = "false"
```

Nos casos onde é necessário realizar uma comparação com dois valores Either de cada vez é necessário utilizar o método `Match2`, este método é consideravelmente mais complexo, pois você terá de lidar com todas as possíveis combinações de resultado.

&#x20;**Utilizando Match2 com dois Either no estado IsRight**&#x20;

```csharp
Either<bool, int> either = 15;
Either<bool, int> either2 = 10;
int result =
    either.Match2(
                  either2,
                  (value1, value2) => value1 + value2,
                  (value1, value2) => value1,
                  (value1, value2) => value2,
                  (value1, value2) => 0
                );
//result = 25
```

Neste exemplo está sendo realizada a soma de dois valores Either diferentes, no caso, ambos com o estado `IsRight`, fazendo com que o primeiro método seja executado:

`(value1, value2) => value1 + value2`

Neste método anônimo o parâmetro `value1` contém o valor armazenado pela variável `either` (10) e o parâmetro `value2` da variável `either2`(15).

Neste exemplo a variável `result` receberá o valor 25.

Para este tipo de comparação existem outros três resultados possíveis dependendo do estado de cada um dos valores Either:

&#x20;**Utilizando Match2 com os estados IsRight e IsLeft, respectivamente**

```csharp
Either<bool, int> either = 15;
Either<bool, int> either2 = true;
int result =
    either.Match2(
                  either2,
                  (value1, value2) => value1 + value2,
                  (value1, value2) => value1, // -> Selecionado
                  (value1, value2) => value2,
                  (value1, value2) => 0
                );
//result = 15
```

&#x20;**Utilizando Match2 com os estados IsLeft e IsRight, respectivamente**

```csharp
Either<bool, int> either = false;
Either<bool, int> either2 = 10;
int result =
    either.Match2(
                  either2,
                  (value1, value2) => value1 + value2,
                  (value1, value2) => value1, 
                  (value1, value2) => value2, // -> Selecionado
                  (value1, value2) => 0
                );
//result = 10
```

&#x20;**Utilizando Match2 com dois Either no estado IsLeft**&#x20;

```csharp
Either<bool, int> either = false;
Either<bool, int> either2 = true;
int result =
    either.Match2(
                  either2,
                  (value1, value2) => value1 + value2,
                  (value1, value2) => value1,
                  (value1, value2) => value2,
                  (value1, value2) => 0 // -> Selecionado
                );
//result = 0
```

Tanto para o método `Match` quanto para o método `Match2` há uma sobrecarga onde os métodos informados não precisam retornar nenhum tipo de valor (`void`).

O conceito dos valores "Ou um ou outro" pode ser encontrado na seção [Conceitos > Valores "Ou um ou outro"](https://github.com/gabrielschade/tango-br/tree/973dafe9d6a8dbad594ebb5c6d71c46ff5727a5a/Concepts/Either%20Values.html).
