dart-lang / language

Design of the Dart language
Other
2.67k stars 205 forks source link

Allow non-const classes to be more efficient on const values #187

Open davidmorgan opened 5 years ago

davidmorgan commented 5 years ago

There are cases where we would like to do defensive copying only when a value is not const.

For example, an immutable list implementation might take a List as input. If the List is not const, it needs to make a defensive copy.

Currently only something that is itself const can be sure to receive const values. This is very restrictive. Lots of immutable collections, for example, use mutable internals for efficiency.

What is requested, then, is a way for non-const classes to know whether a value is const and behave differently. One feature that would satisfy this would be a way to specify an alternative constructor that is used when the values passed in are const:

class ImmutableList<T> {
  final List<T> list;

  // This will be called if `list` is `const`.
  ImmutableList(const List<T> list) : this.list = list;

  // This will be called if `list` is not `const`.  
  ImmutableList(List<T> list) : this.list = list.toList();
}

Further, 'auto const' would apply in these contexts, allowing:

ImmutableList([1, 2, 3])

to allocate a const list and avoid copying altogether.

The idea is just for illustration--the request is to give a way to avoid defensively copying const values.

Thanks!

eernstg commented 5 years ago

This issue would also be closely related to #125, because immutability also ensures that an instance can be shared freely. To make these two play well together, we would need to make sure, as far as possible, that the immutability of the value of a constant expression is known during static analysis.

lrhn commented 5 years ago

I agree that a general notion of deeply immutable values, separate from const values, would probably be useful and solve some issues like this.

An immutable object could be any object created from a const constructor with only immutable arguments (that ensures that you can't introduce mutability) and some system created collections (like the result of List.unmodifiable when all elements are immutable).

If we had such a property reflected in the run-time values, then it would be possible to ask whether Object.isImmutable(anything). There would still be no way to detect whether a list of mutable objects is itself unmodifiable. That's a logical property, not a physical one (one logical object may consist of multiple different physical objects, and the language can not be expected to know the logical boundaries), whereas deep immutability is a physical property of the object graph independent of logical boundaries.

(I worry when I see people using const for only the immutability, because they do also pay for the canonicalization and compile-time evaluation, if nothing else it restricts what you can put into the const object). If we had (run-time) canonicalization or immutability separate from const-ness, then some problems might be easier to solve.

kevmoo commented 5 years ago

See also https://github.com/dart-lang/language/issues/117

I wish I could do var myData = ^[a, b, c]; to get an immutable list from non-const values