built_collection do Dart para Coleções Imutáveis
Há um mês, eu falei na Dart Developer Summit sobre modelos de objetos com source_gen (vídeo). Mencionei alguns pacotes e técnicas que merecem…
Há um mês, eu falei na Dart Developer Summit sobre modelos de objetos com source_gen (vídeo). Mencionei alguns pacotes e técnicas que merecem uma olhada mais de perto, então estou aqui para contar a história completa.
Primeiro, o built_collection.
O pacote built_collection oferece coleções no estilo do SDK com imutabilidade. Imutabilidade para:
-
Simplicidade e conveniência. Uma coleção imutável pode ser passada adiante sem se preocupar com quem pode modificá-la.
-
Desempenho. A mutabilidade leva a padrões caros, como cópias defensivas e detecção de mudanças.
O fato de o built_collection ter que ser conveniente impõe alguns desafios à API. Vamos dar uma olhada. Primeiro, uma lista imutável:
var list = new BuiltList<int>([1, 2, 3]);
Agora eu gostaria de adicionar um valor a ela. Claro, ela é imutável, então não posso; o que eu realmente quero é criar uma nova lista com um valor extra no final.
É aqui que encontramos o padrão builder, que dá nome ao pacote. Você obtém uma nova lista convertendo para um builder, fazendo as modificações e depois construindo:
var builder = list.toBuilder();
builder.add(4);
var newList = builder.build();
Builders geralmente são usados inline, então vamos fazer isso:
var newList = (list.toBuilder()..add(4)).build()
Isso é o máximo que o padrão builder costuma alcançar, mas o Dart tem lambdas, então podemos fazer melhor:
var newList = list.rebuild((b) => b.add(4));
O que descobrimos é que a cascata de métodos do Dart torna o padrão builder muito poderoso. Você quase sempre consegue fazer o que quer inline:
var newList = list.rebuild((b) => b
..add(4)
..addAll([7, 6, 5])
..sort()
..remove(1));
Então, como esperado, o built_collection é conveniente.
Vamos falar de desempenho.
As Built Collections estão atualmente otimizadas para código que tem um ciclo de atualização/publicação. Isso significa: as coleções são convertidas para um builder, atualizadas, construídas e então publicadas — uma referência é passada — para o restante do código consumir.
Isso se encaixa no uso típico em aplicações web, por exemplo apps Angular. Nelas, uma interação do usuário ou uma resposta de RPC dispara uma atualização. O modelo de dados é reconstruído antes de ser publicado para renderização.
As Built Collections ainda não são otimizadas para reconstruções muito frequentes, o que exigiria implementar sobre estruturas de dados cuidadosamente escolhidas. Se você tem um caso de uso para isso, entre em contato — faz parte do design das Built Collections que isso seja possível quando for necessário.
Além da imutabilidade, o built_collection ajuda você a escrever código bom e correto. Um conjunto de propriedades ajuda nisso:
- Built Collections precisam ser criadas com parâmetros de tipo explícitos; não existe algo como um BuiltList<dynamic>.
new BuiltList([1, 2, 3]); // Throws an exception!
new BuiltList<int>([1, 2, 3]); // Better.
- Os valores precisam ser não nulos; nulos não podem ser adicionados a uma Built Collection.
new BuiltList([1, 2, null]); // Throws an exception!
- Built Collections são comparáveis e possuem hash. Isso significa que você pode colocá-las em maps, sets e multimaps, criando exatamente as coleções que combinam com seus dados.
Essas propriedades são especialmente adequadas para coleções de objetos de negócio: em uma aplicação web de loja, por exemplo, para guardar o conteúdo atual do carrinho de compras do usuário.
Foi uma visão rápida do que o built_collection oferece e do porquê; mais informações estão disponíveis na página do GitHub. Para aproveitar bem as coleções imutáveis, porém, você precisa de classes imutáveis. Próximo passo: built_value!
Edição: próximo artigo.
Mais do Dart
Trazendo construtores primários para o Dart
Um olhar por dentro das decisões de design, dos trade-offs e do açúcar sintático por trás da adição de construtores primários no Dart 3.13.
A história da interop com JS no Dart
O suporte ao Wasm acaba de chegar ao Flutter beta atual, graças a um marco empolgante de interop com JavaScript alcançado no Dart 3.3. Para celebrar…