dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.04k stars 1.55k forks source link

Value types (deep immutability) #501

Open DartBot opened 12 years ago

DartBot commented 12 years ago

This issue was originally filed by domi...@google.com


I would like to suggest the addition of 'readonly' as a keyword to complement 'final'. It's use should instruct the compiler to enforce the deep immutability of the variable it describes. This is useful to people using an API, and provides strong hints for optimization possibilities for the compiler and VM.

For example, this is legal:

  Bar mybar;   foo(mybar);

  void foo(final Bar bar) {     bar.thing = other_thing;   }

I suggest that:

  Bar mybar;   foo(mybar);

  void foo(readonly Bar bar) {     bar.thing = other_thing;   }

should be illegal and should error during compilation when assignment to bar.thing is attempted.

Similarly, any attempt to take a non-readonly reference to a readonly variable should be illegal.

This may require methods on an object to be marked as readonly to indicate that they don't mutate |this|, though it may be possible to statically determine this.

gbracha commented 12 years ago

Deep immutability is a very useful concept. Unlike shallow immutability (final) it isn't a property of a variable however - it is a property of an object. It just won't be useful if another reference to that object can make changes to it.

Deep immutability is a complex issue. It would be nice to have, but it will take some time to see if we can come up with a workable solution.


Set owner to @gbracha. Removed Type-Defect label. Added Type-Enhancement, Area-Language, Accepted labels.

gbracha commented 12 years ago

Changed the title to: "Value types (deep immutability)".

DartBot commented 12 years ago

This comment was originally written by mattsh@google.com


Just to clarify or emphasize what's already stated above, immutability and readonly are different concepts. (You might have a readonly view of an object that can be mutated by something else.)

Also, related, we currently have interface FrozenElementList used by some DOM APIs.

DartBot commented 12 years ago

This comment was originally written by domi...@google.com


Thank you for clarifying. My original intent was for readonly as a property of a var. Ie, you can create a readonly reference for the scope of a method, or you could define a class member as readonly which would require it to be set at construction.

Creating a non-readonly reference to a reference that has been marked readonly would be a compile time error (as I believe it can be statically determined). Similarly, calling non-readonly methods on a readonly reference would be an error, though I'm not sure if that can be determined statically without some annotation from the developer on the method.

DartBot commented 12 years ago

This comment was originally written by @yjbanov


I think it is worth a consideration, although I'd recommend the more familiar keyword "const" rather than "readonly", since one of the major goals is to keep the language as familiar as possible to programmers of existing languages, in this case C#/C++.

A related topic is read-only API for certain core Dart classes. I posted a proposal (includes a working prototype) for a read-only API for some of Dart's core collections:

http://goo.gl/R30KV

Which grew out of this long discussion:

http://goo.gl/4Jo0a

Yegor

anders-sandholm commented 12 years ago

Added this to the Later milestone.

DartBot commented 11 years ago

This comment was originally written by @polux


I would be so glad to see this happening. Here are some thoughts:

  - Dart could provide deep immutability by construction (you can only construct a deeply immutable value from deeply immutable values), and this could be enforced at runtime, even in unchecked mode. The downside of this approach is that it requires a very functional style and makes the building of graphs almost impossible (unless you comme up with some notion of lazy values, I guess).

  - Alternatively, we could have a "freeze" operator which would mean "from now on, this value is deeply immutable". Then checked mode would check that none of its recursively subvalues is ever modified. I guess that would be very costly but on the other hand it would offer an unprecedented flexibility.

  - A variation around the alternative is to freeze by copy, which would make the subsequent checks much easier, but would induce possibly unbearable runtime costs.

kasperl commented 10 years ago

Removed this from the Later milestone. Added Oldschool-Milestone-Later label.

kasperl commented 10 years ago

Removed Oldschool-Milestone-Later label.

davidmorgan commented 8 years ago

FYI https://github.com/google/built_value.dart is a library that uses codegen to support value types. If you use it for all your types, you have deep immutability.

stephenbunch commented 4 years ago

Reviving an old thread. We use built_value, but we also like free-handing objects. With NNBD, I'm planning to roll out some best practices to our team for free-handed immutables:

class Foo {
  final int bar;

  Foo(this.bar) {
    // hashObjects([bla, bla]) from quiver library
    hashCode = bar.hashCode;
  }

  /// The `late` keyword is coming with NNBD.
  @override
  late final int hashCode;

  @override
  bool operator ==(dynamic other) =>
      // Short-circuit identical objects. BTW, BuiltValue does this already.
      identical(other, this) ||
      (other is Foo &&
      // Short-circuit unequal objects.
      other.hashCode == hashCode &&
      // Proceed to check each value individually.
      other.bar == bar);
}

I wonder if it's possible to create a language syntax that does the same thing?

immutable class Foo {
  final int bar;

  Foo(this.bar);
}
davidmorgan commented 4 years ago

FWIW, and as the author of built_value I'm almost certainly biased ;) I don't think NNBD is enough to make hand-maintaining immutable value types a good idea. I wrote an article about all the problems with hand maintained immutable value types ;) https://medium.com/@davidmorgan_14314/the-mutability-tax-6403d84f21c0