dart-lang / language

Design of the Dart language
Other
2.65k stars 202 forks source link

Records, how to assign them to Objects of the same shape #1313

Open escamoteur opened 3 years ago

escamoteur commented 3 years ago

When reading @munificent 's great summary on records I started to wonder what about assignment by value between records and Objects with the same shape, so that you could easily initialize Objects from an existing record.

Maybe even the other way round, so that inside a function that returns a record type you could use a real class Object but could return it if it has the same shape.

lrhn commented 3 years ago

That would very much depend on what the "shape" of a class instance is.

Tuples/records are defined by their structure: How many positional elements, which named elements (and their types). Objects are not. Objects do have fields (instance variables), but a private field is an implementation detail, and exposing it in any way not intended by the class author is a breach of abstraction. That's definitely not something we want to do (you want to look at implementation details, you have to use reflection).

The "shape" of a class instance is its public API. If you want to expose some parts of the object state, you provide getters or methods which return it. Sometimes the internal state matches the external API (and then you can have public fields), but the next release of the same code can change that to a public getter/private field without anybody noticing.

So, if a class instance want to be assignable to or from record types, we need some explicit opt-in from the class. At that point, they can also just add ... toTuple() and static fromTuple(...) methods, no extra functionality or implicit coercions needed.

lrhn commented 3 years ago

What is the purpose of allowing a class instance to implement a tuple type? If you can use it interchangeably with tuples values, then all tuples will need to be boxed, which removes a lot of the benefit of having tuples anyway. You can already do what you're describing here with classes and interfaces.

I guess this goes back to the fundamental question: Why do we want to add tuples at all?

escamoteur commented 3 years ago

a to/fromRecord creates again boilerplate code. If a Object has matching public fields an assignment would be possible. toRecord should be possible without a problem

instead of fromRecord I could also imagine that if you have a constructor with the shape of a record that you can pass a record directly to a constructor. Or following this thought allowing to assign a record to functions with a matching signature.

xxgreg commented 3 years ago

One approach would be to allow records to be spread into function and constructor calls.

(I think this has been discussed here somewhere in another issue.)

For example:

class Foo {
  Foo(this.a, {this.b, this.c});
  final int a;
  final int? b;
  final int? c;
}

var r = (1, b: 2, c: 3);

var f = Foo(...r);