Rilevare quando un oggetto const viene passato a una funzione che lo modifica, in Dart

Aug 17 2020

Prendi questo esempio:

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

L'esecuzione del codice precedente risulta in un runtime Uncaught Error , ma la rimozione del file constda

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

gli permette di funzionare.


Questo mi sembra un bug perché la variabile const può essere mutata e dart lo rileva in fase di esecuzione, il che significa che ha i mezzi per rilevare quando un oggetto const viene modificato, ma non avrebbe dovuto essere rilevato in fase di compilazione, visto come le variabili const sono chiamate " costanti in fase di compilazione ".

Se questo non è un bug, c'è qualcosa in dart che ci permette di rilevare in fase di compilazione quando una constvariabile potrebbe essere mutata da un'operazione?

In C ++, il compilatore genera errori quando proviamo a fare qualcosa di simile. C'è qualcosa che possiamo fare in Dart per evitare di riscontrare questo errore in fase di esecuzione?

Risposte

3 lrn Aug 17 2020 at 04:53

No. Dart constè una funzionalità in fase di compilazione relativa alla creazione di oggetti, ma non si riflette nel sistema di tipi. Non puoi dire dal tipo di qualsiasi oggetto se è una costante o meno.

Di solito questo non è un problema perché un'istanza di una classe che può essere const non è modificabile. Non è garantito che sia profondamente immutabile, ma non è possibile modificare i campi dell'istanza stessa.

Liste, insiemi e mappe possono essere sia costanti che mutevoli. Questo è quello che vedi qui. L'argomento della lista a const Foo(const [1, 2, 3, 4])è costante, anche se rimuovi il ridondante constdal letterale della lista. Avresti lo stesso problema con new Foo(const [1, 2, 3, 4]), che fornirebbe anche un immutabile foo.bar, ma da cui altrimenti sarebbe indistinguibile new Foo([1, 2, 3, 4]). L'unica vera differenza è se l'elenco è modificabile o meno, e l'unico modo per rilevarlo è provare a modificarlo.

Liste, set e mappe non forniscono alcun modo per rilevare se sono modificabili o meno, tranne provare e rilevare l'errore.

Quando si confronta con C ++, la nozione di essere di Dart constè una proprietà dell'oggetto o, in realtà, il modo in cui l'oggetto viene creato. Ciò potrebbe avere alcune conseguenze per l'oggetto. A const Foo(..)crea semplicemente un Foooggetto normale , ma può solo creare oggetti profondamente immutabili e sono canonizzati. A const [...]o const {...}crea un diverso tipo di elenco / mappa / insieme rispetto al valore letterale non const, ma non è visibile nel tipo.

In C ++, being constè una proprietà di un riferimento a un oggetto e limita il modo in cui tale riferimento può essere utilizzato, ma non ci sono oggetti costanti in quanto tali. Qualsiasi oggetto può essere passato come constriferimento.

I due concetti sono di natura completamente diversa e per caso usano lo stesso nome (e sono anche entrambi diversi da JavaScript const).