Détecter quand un objet const est passé à une fonction qui le mute, dans Dart
Prenons cet exemple:
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'exécution du code ci-dessus entraîne un runtime Uncaught Error
, mais la suppression const
de
var foo = const Foo([1,2,3,4]);
lui permet de fonctionner.
Cela me semble être un bogue car la variable const peut être mutée et dart le détecte au moment de l'exécution, ce qui signifie qu'il a les moyens de détecter quand un objet const est modifié, mais cela n'aurait pas dû être détecté au moment de la compilation, vu que Les variables const sont appelées « constantes à la compilation ».
Si ce n'est pas un bogue, y a-t-il quelque chose dans dart qui nous permet de détecter au moment de la compilation quand une const
variable sera éventuellement mutée par une opération?
En C ++, le compilateur se trompe lorsque nous essayons de faire quelque chose comme ça. Y a-t-il quelque chose que nous pouvons faire dans Dart pour éviter de rencontrer cette erreur lors de l'exécution?
Réponses
Non. Dart const
est une fonctionnalité de compilation autour de la création d'objets, mais elle n'est pas reflétée dans le système de types. Vous ne pouvez pas dire d'après le type d'un objet s'il s'agit d'une constante ou non.
Ce n'est généralement pas un problème car une instance d'une classe qui peut être const n'est pas modifiable. Il n'est pas garanti qu'il soit profondément immuable, mais l'instance elle-même ne peut pas voir ses champs modifiés.
Les listes, ensembles et cartes peuvent être à la fois constants et mutables. C'est ce que vous voyez ici. L'argument de liste à const Foo(const [1, 2, 3, 4])
est constant, même si vous supprimez le const
littéral redondant du littéral de liste. Vous auriez le même problème avec new Foo(const [1, 2, 3, 4])
, qui fournirait également un élément immuable foo.bar
, mais qui serait autrement impossible à distinguer de new Foo([1, 2, 3, 4])
. La seule vraie différence est de savoir si la liste est modifiable ou non, et le seul moyen de le détecter est d'essayer de la modifier.
Les listes, ensembles et cartes ne fournissent aucun moyen de détecter s'ils sont mutables ou non, sauf en essayant et en détectant l'erreur.
En comparaison avec C ++, la notion d'être de Dart const
est une propriété de l'objet ou, en réalité, la façon dont l'objet est créé. Cela peut avoir des conséquences sur l'objet. A const Foo(..)
crée simplement un Foo
objet normal , mais il ne peut créer que des objets profondément immuables et ils sont canonisés. Un const [...]
or const {...}
crée un type de liste / carte / ensemble différent du littéral non const, mais ce n'est pas visible dans le type.
En C ++, être const
est une propriété d'une référence d'objet et restreint la façon dont cette référence peut être utilisée, mais il n'y a pas d'objets constants en tant que tels. Tout objet peut être passé comme const
référence.
Les deux concepts sont de nature complètement différente et utilisent simplement le même nom (et sont également tous deux différents de JavaScript const
).