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
Add data classes #314
Comments
No promises, but it's on the radar.. |
Or inline make it shorter?
|
Are there any updates on this enhancement? I'm currently working with Flutter, and having come from the Kotlin/Android world, this is something that would make the transition a lot nicer. Especially when creating ViewModels, or even simple data models, this would make it a lot easier. |
@dcovar don't expect anything short term. It won't be part of Dart 2. |
Community could write a package similar to Lombok who autogenerates code from a valid annotated source code file. One more thing for the wishlist on either flutter/flutter#13607 or flutter/flutter#13834, not sure which |
|
One thing worth mentioning is that data classes and sealed classes can both be viewed as an instance of a metaclass. If enough different kinds of special-cased classes are proposed, at some point it might become better to add metaclass programming to the language, with a few individual cases of syntax sugar. Dart already kind of flirts with the idea when you look at what was needed to make the mirrors API work. |
I support this, but suggest also adding |
@andrewackerman Data classes shouldn't have more than a generic minimum to be used as domain entities, this being |
@i-schuetz Then maybe there can be some optional attributes that can be added to the class declaration so these features can be added for people who need them? Serialization may not be a universal requirement but I'd bet that it would be needed often enough that people would want to at least have the option. Otherwise it would largely defeat the purpose of having a concise data class declaration syntax but then have to manually create the (de)serialization methods. And it's not like it would need to serialize to actual JSON strings. It could serialize to |
Maybe something generic along the lines of Swift's |
I agree with @i-schuetz that adding a |
@leafpetersen @munificent @lrhn – should be moved to the language repo? |
yes, thanks. |
Let's kill the argument that moving to Dart (Flutter) from Kotlin is like moving back in time several years. |
The point of having data classes (apart from immutability) is to have implicit methods e.g. toString(), hash(), == for free. More importantly for immutable class there is a need for mutation method (e.g. Kotlin apply() aka copyWith() in other languages) with default implementation to avoid boilerplate of mutation method. |
Hello, This proposal is great and could attract more developer like me. Do you know when it could be implemented ? |
@benoit-ponsero is the method copy done by reflection? |
It's a compiler generated method. |
Then it must be tree-shaken when built with dart2js. |
Here in our company we are crossing our fingers to get this feature arrive son! |
I'm also hoping that this will be added, a way to have a default implementation of |
For a more lightweight alternative to |
I disagree. Asserts are quite important for data-classes IMO. And so are default values or the ability to mix both named and positional parameters. In particular, I think a very common use-case for data-classes is a "config" class, such as But with the current proposal, it is not feasible to do something like |
There's no refactoring if we don't have meta-programming yet. They already have a constructor, the question is can they remove it.
Besides for what I see to be obvious readability, I wrote a comment at #1769 (comment) addressing that. |
The problem isn't going from nothing to static-metaprogramming. My point is about refactoring a class that is already using the Say we have: @data
class Example {
final String a;
final String b;
} And we are now tasked with adding a base class (or default values, or anything else requiring a constructor). Then the change would be: @data
- class Example {
+ class Example extends Base {
+ const Example(
+ this.a,
+ this.b,
+ ): super.named(a: a);
final String a;
final String b;
} We suddenly have to write the full constructor, which is inconvenient and verbose. Whereas with a the constructor-first approach, the diff would be: @data
- class Example {
+ class Example extends Base {
const Example(
this.a,
this.b,
- );
+ ): super.named(a: a);
} With this approach, only what is necessary changed.
I answered those points, which I disagree with. |
I wasn't really judging by "how many lines would you add in a specific scenario". I was focusing on "omitting a constructor means let the macro take over, but explicitly setting one indicates that you want to do it manually", which is a pretty intuitive structure, similar to inheritance: you inherit members by default, but can also override them when needed. But that's just my opinion. As @munificent said, the point of making macros general is that you should be able to create your own macros (and modify existing ones) easily. Even if overriding user code isn't allowed, you can still do something like this: @dataFromConstructor
class Person {
const Person._( // is only used for code-gen purposes
final String name, {
final int age = 0;
}): assert(age >= 0);
}
// generates:
class Person {
final String name;
final int age;
const Person(this.name, {this.age = 0}) :
assert(age >= 0);
} Or maybe you decide that @dataFromConstructor(Person._codeGenSpec)
class Person {
const Person._(); // other work done here
const Person._codeGenSpec( // is only used for code-gen purposes
final String name, {
final int age = 0;
}) : assert(age >= 0);
} Point is, metaprogramming should allow this to be part of your design, so we don't really need to have an "official" macro for each scenario. |
Asking users to define a private element, so that macros can then generate a variant with a desired name is IMO a bad solution. This hinders the ability for users to control the publicity of an element. Folks may want to make a constructor private. Using this solution, we would need a gimmick tell macros whether the generated constructor should be public or not, which is undesired because this moving away from the existing conventions.
Official macro or not, I believe this is still an important discussion to have. My argument is that it is only a temporary fix, as no-matter which approach we take, we would suffer from various limitations. We would lose features or have to degrade the syntax. Ultimately I think we should split the problem into two:
IMO while I agree that static metaprogramming is a good solution to the second point, I think the first point still should be solved by the language instead of macros. Dart could natively support: const class Person(final String name, {final int age = 0}); as a syntax sugar for defining a constructor + properties: class Person {
const Person(this.name, {this.age = 0});
final String name;
final int age;
} And then we could combine it with macros for everything else: @data // generates ==/toString/copyWith/...
const class Person(final String name, {final int age = 0}); This way we solve the problem of extracting opinionated logic out of the language, but we don't compromise on the syntax. |
It is not a syntax sugar to final properties, but Dart already accepts class Foo {
String buf;
Foo({required final String buffer}): buf = buffer;
} |
I have been following this issue for a while now seen a lot of proposals
For optional fields use null safety and let the programmer shot him/her self in the foot in terms of positioning fields:
And lets use every time I use freeze I never want to look at my code is a lot and looks "messy" |
This is almost exactly as Kotlin implementation.
|
Where is the issue, I want that too, the ability to add methods inside those data classes. |
The issue here is that your version doesn't use any constructor, so you can't distinguish between your data field and any other field. Example: data class User {
String firstName;
String lastName;
} but you'd want to create computed property data class User(
val firstName: String,
private val lastName: String
) {
...
} So you separate those autogenerated fields from anything else. I think this is better. |
any pub package to achieve data class? like kotlin's syntax |
https://pub.dev/packages/equatable
But is not the same as you still need to add fields manually.
W dniu śr., 8.09.2021 o 20:03 Erlang Parasu ***@***.***>
napisał(a):
… any pub package to achieve data class? like kotlin's syntax
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#314 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAMOAXH3LHYM63FRZHWRSX3UA6QQDANCNFSM4HFWZY3A>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
|
Possible unpopular opinion, but I'd be okay with data classes only having named arguments. |
These sorts of data class seem to be industry standard now in most modern languages. It would really be nice if dart team would make this a first class feature rather than relying on meta-programming. Meta-programming is great for plugging holes quickly, but this seems like a more fundamental thing that should just be part of the language and there are several implementations to look at now for reference. |
Exaclty. And while you guys argue here about how to implement this because there are mixed feelings about this. There are references in other languages. For me kotlin is the best example here.
|
Like I think there's a good argument to make that the pure cludge of having a .g file for basic data class features should almost disqualify it from meta-programming as a final solution. You're talking about the difference between:
That's the entire thing, we get what everyone wants, a nice solid little immutable dataclass. No extra files, no extra links, no extra steps it's baked into the language as a first class type. Compare to:
+Another file of many lines. Think of the extra clutter across a codebase, the hassle when declaring small data classes within a larger file, the general cruft of it all spread around, the general pain when I refactor and want to move a class to another file. |
My 2 cents... The verbosity of the meta-programming example is not that bad - I think the case is a tad over stated... It's easy to add features to a language (C++) but impossible to remove them later. A powerful, but general purpose extension model (via meta-programming) seems like a good idea that should be explored before further language changes are made. data classes might still be a good idea - but let's see how far meta programming can take us.. |
It's not just the verbosity of the code you write, it's the general messiness of splitting code across 2 files, over and over again, all over your project. Also, coming from the standpoint of 'we need this yesterday', it seems like this might be a more linear path than meta-programming. It's a clear focused feature with not a lot of ?'s, whereas meta-programming, has many more use cases and complications, and who knows when it will ever actually land. |
While I'd like faster releases as much as the next person, it seems like static meta programming is high on the priority list. https://github.com/dart-lang/language/projects/1 Static meta programing issue was opened in march 2021 and already moved to being spec'ed. As a comparison this feature #1072 which is being implemented was opened in 2013. So there is hope. I do agree that something, not specifically data class, but even records, should be part of the the language though. For a language that is marketed at being a client sided language it seems mandatory. |
I've been lurking this thread for a couple years and I want to say that it would be really nice if Dart could simply have structs or data classes or anything really, I just want to do this, (although it could be considered kind of un-Dart-like) struct Person {
String name;
int age;
// null by default
bool? married;
}
void main() {
final john = John(
name: "John",
age: 44
);
// or either
final Person john = {
name: "John",
age: 44
};
// the former ^ is more Dart-like, imo
// prints `null`
print(john.married);
} Edit: thread's coming up on 5 years open now... |
@AfricanElephant I guess that is closer to the Records proposal |
@jodinathan That link goes to edit: cropped the image so it's smaller |
@AfricanElephant edited |
Just my two cents
define class
then, remove "final int" and write "required this." for constructor
then, remove "required this." and write ": 0" to call it
So let's add new syntax define data-class (not like class syntax, you can call this params)
we need just copying them, and change "int" to params "0", "1", "2" |
All those keyword you mentioned add value to the api you create. Required will make sure that if you forget a parameter the IDE will complain, or even the compiler I'm not sure., final will make sure that the variable can't be changed etc, But I'm sure you know that already. To be honest, my personal opinion is that those are backward, those should be the default, always more restrictive by default so to speak and we would add optional when needed, because most of the time that's what we want. But that's just not how it is and all things considered it's not so ba. In your example, would a,b and c be required or optional ? |
I don't think there's need for the If it's nullable -> it's not required But I would still rather have the |
@cedvdb @VKBobyr
About "required" keyword, there is another proposal. Sorry for all my strange ideas and words. I'm on your side. |
Immutable data are used heavily for web applications today, commonly with Elm-like (redux, ngrx, ...) architectures. Most common thing web developer is doing with data is creating a copy of it with some fields changed, usually propagated to the root of state tree. JavaScript has spread operator for this. There should be a easy way to use immutable data structures in Dart. I would like to have data classes (inspired by Kotlin) in Dart. Possible API:
Compiler assumes that all fields of data class are immutable. Compiler adds
equals
implementation based on shallow equals,hashCode
implementation based on mix of all object fields,toString
implementation of the form<Type> <fieldN>=<valueN>
, andcopy
function to recreate object with some fields changed.You may argue that there is already Built value package that allows to do similar things, but we have many issues with package, mainly:
I have found that using built value actually decreases my productivity and I do my work faster with even manually writing builders for classes.
If data classes would be implemented on language level, it would increase developer productivity and optimizations can be made when compiling code to particular platform.
The text was updated successfully, but these errors were encountered: