-
Notifications
You must be signed in to change notification settings - Fork 213
Records: Should functional update be allowed to change the type? #1319
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Since functional update creates a new object, there is no issue with it creating something of a new type. You might not be able to assign it back to the original variable, but that's not necessarily a problem. Also, the type of the original object isn't as interesting as its static type. If we have: However, if you are allowed to "replace as single value" from a tuple to have a completely different type, then there is no longer any type relation between the original and the new value. So, why can't you also add more values or remove values entirely from the original? In short, why are you not just building a new value from scratch instead of "replacing" in the existing value? The answer will likely be "it's shorter", which suggests that we might just want shorter syntax for more general projections, so instead of Is "replacing specific values" just a special case of building a new tuple containing some values of an existing tuple? Should we support the more general case instead? |
FWIW, F# has no problem with this: let myRecord2 = {| X = 1; Y = 2; Z = 3 |}
let myRecord3 = {| myRecord2 with X = "hello" |} Ocaml and Haskell records are (I think) always named, so this would mostly come up with polymorphic records. Ocaml at least doesn't seem to allow changing the type of a polymorphic field with a |
@lrhn wrote:
This is exactly the point I'm making: The ability to express and maintain a connection between such types is new to Dart, because they are unrelated according to the existing type system. In other words, this enhances the expressive power of the type system. The benefit derived from this feature is consistency and abstraction: if a record/tuple The context may then have to be edited such that it works with the new structure of data (this is a good thing), or the new type may propagate implicitly through the context because it abstracts away from the details that differ (this is even better). In contrast, if we use a record/tuple literal If the change goes from
I mentioned this possibility, noting that the ability to build a new shape would be somewhat costly: We'd need syntax and language mechanisms to specify record/tuple shape incrementally. If we can come up with an elegant design for doing this then the benefits described above would just apply to a broader range of situations, which is great!
Because that new value would not be as abstract, and we would miss out on the ability to maintain consistency as described above. Conciseness is another benefit, but that is much, much less important.
This is the incremental shape specification I just mentioned, and it would indeed be more powerful. But the shape preserving @tatumizer wrote:
My preference would be that the With a concrete record type the shape of the receiver is statically known. This ensures that the operation can have good performance (a |
@munificent, as far as I can see we aren't actually doing anything like |
Yes, we aren't going to get any kind of record update in the initial release. |
Sounds good that it might come later on! ;-) |
Issue #1292 seems to gather broad support for a mechanism where an existing record/tuple whose static type is a concrete record type is used as a template in the creation of a new one, just differing at the components that are mentioned. The syntax could for instance be as follows:
This mechanism gives rise to a language design decision with respect to the type of the result:
We may require that each actual argument of the
with
construct has a type that is a subtype of the static type of the corresponding component of the receiver. This allows the result to be re-assigned to a variable:Alternatively, we could relax the requirement such that it must be a subtype or a supertype, or we could leave the type entirely unconstrained:
Pro:
Pair<T1, T2>
andPair<S1, S2>
can be seen as related because both havePair<Object?, Object?>
as a supertype), but that connection does not allow for abstractions over transfer of state, or any other operations involving "all components", so this would bring something new to Dart.Con:
We could also consider changing the shape of the result, but that seems less attractive: It would require a non-trivial amount of syntactic support to allow components to be dropped or added. It's probably better to require that new shapes are expressed using a record/tuple literal, where we already have well-known syntax for specifying the shape.
The text was updated successfully, but these errors were encountered: