Detectar cuando un objeto constante se pasa a una función que lo muta, en Dart

Aug 17 2020

Toma este ejemplo:

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);
}

Ejecución de los resultados anteriores de código en un tiempo de ejecución Uncaught Error , pero la eliminación de la constde

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

permite que funcione.


Esto me parece un error porque la variable const se puede mutar y dart lo detecta en tiempo de ejecución, lo que significa que tiene los medios para detectar cuándo se modifica un objeto const, pero ¿no debería haberse detectado en tiempo de compilación? Las variables const se denominan " constantes en tiempo de compilación ".

Si esto no es un error, ¿hay algo en dart que nos permita detectar en el momento de la compilación cuándo una constvariable posiblemente será mutada por una operación?

En C ++, el compilador falla cuando intentamos hacer algo como esto. ¿Hay algo que podamos hacer en Dart para evitar encontrar este error en tiempo de ejecución?

Respuestas

3 lrn Aug 17 2020 at 04:53

No. Dart constes una función en tiempo de compilación relacionada con la creación de objetos, pero no se refleja en el sistema de tipos. No se puede saber por el tipo de cualquier objeto si es una constante o no.

Por lo general, eso no es un problema porque una instancia de una clase que puede ser constante no se puede modificar. No se garantiza que sea profundamente inmutable, pero la instancia en sí no puede cambiar sus campos.

Las listas, conjuntos y mapas pueden ser tanto constantes como mutables. Eso es lo que estás viendo aquí. El argumento de la lista const Foo(const [1, 2, 3, 4])es constante, incluso si elimina el redundante consten el literal de la lista. Tendría el mismo problema con new Foo(const [1, 2, 3, 4]), que también proporcionaría un archivo inmutable foo.bar, pero que de otro modo sería indistinguible de new Foo([1, 2, 3, 4]). La única diferencia real es si la lista es modificable o no, y la única forma de detectarlo es intentar modificarla.

Las listas, conjuntos y mapas no proporcionan ninguna forma de detectar si son mutables o no, excepto intentar y detectar el error.

En comparación con C ++, la noción de ser de Dart constes una propiedad del objeto o, en realidad, la forma en que se crea el objeto. Eso puede tener algunas consecuencias para el objeto. A const Foo(..)simplemente crea un Fooobjeto normal , pero solo puede crear objetos profundamente inmutables, y se canonicalizan. A const [...]o const {...}crea un tipo diferente de lista / mapa / conjunto que el literal no constante, pero eso no es visible en el tipo.

En C ++, being constes una propiedad de una referencia de objeto, y restringe cómo se puede usar esa referencia, pero no hay objetos constantes como tales. Cualquier objeto se puede pasar como constreferencia.

Los dos conceptos son de naturaleza completamente diferente y simplemente usan el mismo nombre (y también son diferentes de JavaScript const).