Detectar quando um objeto const é passado para uma função que o transforma, no Dart

Aug 17 2020

Veja este exemplo:

void modl(List<int> l) {
  l.add(90);
  print(l);
}

class Foo {
  final List<int> bar;
  const Foo(this.bar);

  @override
  String toString() => 'Foo{bar: $bar}';
}

void main() {
  var foo = const Foo([1,2,3,4]);
  modl(foo.bar);
  print (foo);
}

Executando os resultados de código acima em um tempo de execução Uncaught Error , mas remover a constpartir de

var foo = const Foo([1,2,3,4]);

permite que funcione.


Isso me parece um bug porque a variável const pode sofrer mutação e o dart detecta isso em tempo de execução, o que significa que ele tem os meios para detectar quando um objeto const é modificado, mas isso não deveria ter sido detectado em tempo de compilação, visto que variáveis ​​const são chamadas de " constantes de tempo de compilação ".

Se isso não for um bug, há algo no dart que nos permite detectar em tempo de compilação quando uma constvariável será possivelmente alterada por uma operação?

Em C ++, o compilador erra quando tentamos fazer algo assim. Existe algo que possamos fazer no Dart para evitar esse erro durante a execução?

Respostas

3 lrn Aug 17 2020 at 04:53

Não. O Dart consté um recurso de tempo de compilação relacionado à criação de objetos, mas não se reflete no sistema de tipos. Você não pode dizer pelo tipo de qualquer objeto se é uma constante ou não.

Normalmente, isso não é um problema porque uma instância de uma classe que pode ser const não pode ser modificada. Não é garantido que seja profundamente imutável, mas a instância em si não pode ter seus campos alterados.

Listas, conjuntos e mapas podem ser constantes e mutáveis. É isso que você está vendo aqui. O argumento da lista para const Foo(const [1, 2, 3, 4])é constante, mesmo se você remover o redundante constdo literal da lista. Você teria o mesmo problema com new Foo(const [1, 2, 3, 4]), que também forneceria um imutável foo.bar, mas que, de outra forma, seria indistinguível de new Foo([1, 2, 3, 4]). A única diferença real é se a lista é modificável ou não, e a única maneira de detectar isso é tentando modificá-la.

Listas, conjuntos e mapas não fornecem nenhuma maneira de detectar se eles são mutáveis ​​ou não, exceto tentar e detectar o erro.

Em comparação com C ++, a noção de ser de Dart consté uma propriedade do objeto ou, realmente, da forma como o objeto é criado. Isso pode ter algumas consequências para o objeto. A const Foo(..)apenas cria um Fooobjeto normal , mas só pode criar objetos profundamente imutáveis ​​e eles são canônicos. Um const [...]or const {...}cria um tipo diferente de lista / mapa / conjunto do que o literal não const, mas isso não é visível no tipo.

Em C ++, ser consté uma propriedade de uma referência de objeto e restringe como essa referência pode ser usada, mas não há objetos constantes como tais. Qualquer objeto pode ser passado como constreferência.

Os dois conceitos são de natureza completamente diferente e usam o mesmo nome (e também são diferentes do JavaScript const).