1 pontos por GN⁺ 2024-08-09 | 1 comentários | Compartilhar no WhatsApp

Resumo

Documento que propõe type unions (ou discriminated unions) em C#.

Motivação

  • No desenvolvimento de software, os valores armazenados em uma variável nem sempre são do mesmo tipo.
  • Por exemplo, quando as definições de cliente e fornecedor compartilham apenas algumas propriedades, pode ser necessário realizar operações semelhantes para os dois tipos.
  • Isso pode ser resolvido com herança, mas nem sempre é adequado para todas as situações.
  • É necessário em C# um modo de armazenar em uma mesma variável um número limitado de tipos diferentes.
  • Outras linguagens já oferecem esse recurso.

Solução

  • A forma mais apropriada de implementar union types em C# pode ser pensada como uma hierarquia usando uma classe base abstrata.
  • Porém, existem problemas como as limitações da hierarquia e a impossibilidade de representar unions de tipos não relacionados.
  • Pode haver necessidade de vários tipos de unions, e esta proposta os classifica em quatro categorias.

Padrão - classe union

Declaração

  • A classe union é declarada de forma semelhante a um enum.
  • Cada membro pode ter variáveis de estado.

Criação

  • É criada atribuindo uma instância do tipo de membro.

Desestruturação

  • É desestruturada por meio de testes de tipo e pattern matching.

Exaustividade

  • Se todos os tipos de membro forem considerados em uma expressão ou instrução switch, não é necessário um caso padrão.

Nulabilidade

  • É possível incluir null usando a notação padrão de nulabilidade.

Implementação

  • A classe union é implementada como uma classe record abstrata.

Especialização - struct union

Declaração

  • É declarada de forma semelhante à classe union, mas com a palavra-chave struct adicionada.

Criação

  • É criada atribuindo uma instância do tipo de membro.

Desestruturação

  • É desestruturada por meio de testes de tipo e pattern matching.

Exaustividade

  • Se todos os tipos de membro forem considerados em uma expressão ou instrução switch, não é necessário um caso padrão.

Nulabilidade

  • É possível incluir null usando a notação padrão de nulabilidade.

Valor padrão

  • A struct union pode ficar em um estado indefinido quando não recebe atribuição ou quando recebe o valor padrão.

Implementação

  • A struct union é implementada como uma struct, e os tipos de membro são implementados como record structs aninhadas.

Temporário - union temporária

Sintaxe

  • A union temporária é referenciada usando a sintaxe de padrão or.

Nomeação

  • É possível dar um nome comum a uma union temporária usando aliases de arquivo ou using global.

Criação

  • É criada atribuindo uma instância do tipo de membro.

Desestruturação

  • É desestruturada por meio de testes de tipo e pattern matching.

Exaustividade

  • Se todos os tipos de membro forem considerados em uma expressão ou instrução switch, não é necessário um caso padrão.

Nulabilidade

  • É possível incluir null usando a notação padrão de nulabilidade.

Intercambialidade

  • Unions temporárias com os mesmos tipos de membro são intercambiáveis.

Union definida pelo usuário

  • É possível declarar tipos union que não podem ser definidos como classe union ou struct union.
  • A hierarquia pode ser fechada usando o atributo Closed.
  • Pode ser implementada como um wrapper struct usando o atributo Union.

Unions comuns

Option

  • É uma struct union que representa um valor que pode existir ou não.

Result

  • É uma struct union que retorna um resultado bem-sucedido ou um erro em uma função.

Propostas relacionadas

Hierarquia fechada

  • Declara um conjunto fechado de subtipos para um tipo base abstrato usando o atributo Closed.

Valor singleton

  • Tipos com um atributo singleton podem ser usados como valor em um contexto que não é de tipo.

Atalho para membro aninhado

  • Permite fazer binding para membros estáticos ou tipos aninhados do tipo de destino usando nomes não vinculados.

Resumo do GN⁺

  • Este documento propõe type unions em C#, oferecendo uma forma de armazenar vários tipos em variáveis em diferentes situações.
  • É uma tentativa de trazer para C# um recurso que outras linguagens já oferecem.
  • Pode ajudar desenvolvedores a melhorar a legibilidade e a manutenção do código.
  • Um exemplo de outra linguagem com funcionalidade semelhante é F#.

1 comentários

 
GN⁺ 2024-08-09
Comentários do Hacker News
  • Já usei uniões discriminadas em F# e achei que C# também tivesse

    • Estou usando Java e sinto que é difícil voltar para uma linguagem sem ADT
    • Fico feliz que não seja mais preciso pedir desculpas pela falta desse recurso importante no C#
  • O termo "união de tipos" me soa estranho

    • Parece semelhante às tagged unions das linguagens da família ML
    • Fico curioso se desenvolvedores C# tendem a criar nomes diferentes dos termos já existentes
  • Como desenvolvedor C# de longa data, sinto que os casos de uso dessa proposta não estão claros

    • Parece algo que poderia ser implementado declarando uma interface vazia e classes record
    • Gostaria de saber se estou deixando passar alguma coisa
  • TypeScript tem uniões de tipos

    • Parece semelhante às uniões discriminadas de F# ou Haskell
    • Uniões discriminadas têm construtores de caso nomeados
  • Programar fica difícil sem uniões com pattern matching

    • Nunca entendi completamente o significado do expression problem
    • Os pontos de extensão oferecidos pelo polimorfismo existente podem ser mais adequados para clientes futuros
    • Para código pertencente à equipe, uniões com pattern matching parecem mais apropriadas
  • Já tive experiência com field offsets em uniões em C#

    • Alias de valores de ponteiro/referência e de valores pode causar comportamento indefinido
    • Uma união em struct entre u64 e um objeto pode exigir um campo separado, desperdiçando 8 bytes
  • Uso construtores privados e um pacote nuget para que tipos switch não precisem de um caso _

    • Isso é semelhante à versão dessugared da "classe união" proposta
    • Seria bom não precisar mais do pacote nuget e ainda ganhar açúcar sintático
  • Não foi mencionado como structs de união lidam com tearing sob modificação concorrente

    • Tearing pode causar problemas de segurança de memória
    • Pode haver variantes com um campo inteiro e um campo de referência no mesmo offset