-
Notifications
You must be signed in to change notification settings - Fork 87
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
Generated RealmObject constructor should use named instead of positional argument #292
Comments
@calvintam236 Thanks for posting. EDIT: for non nullable properties with default values we do generate named arguments as well. |
Thanks for getting back.
See this quote from Effective Dart: In fact, you can just make the constructor with required named arguments: Hello({
required String key,
required String sth1,
required String sth2,
required String sth3,
Iterable<String> listA = const [],
Iterable<String> listB = const [],
}) This would just better for everyone.. Even pre-alpha way |
@calvintam236 Certainly there are choices to be made and we try to optimize for the majority of the use cases. We have indeed consider your suggestion when we implemented the code generator and decided not to implement it this way, since this will require even more typing that it needs to be. Most importantly it hurts the experience in the majority of the cases where there limited number required arguments. for example: class _Person {
@PrimaryKey()
final String name;
} //this
var person = Person(name: "Myname");
//instead of this
var person = Person("MyName") We believe we struck a good middle ground with the generated code and majority of the developers use an IDE these days so it helps in the rare case of 10 or more required fields. cheers |
Instead of changing If you are using IDE, it will autocomplete as The code should always be CLEAR to read and understand. That's the priority. Inconvenience is second. class _Person {
@PrimaryKey()
final String firstname;
final String lastname;
}
Person("last name", "first name"); // difficult to identify
Person(firstname: "last", lastname: "first"); // easy to identify this is WRONG Confusing fields like this example will often happen. This is avoidable yet decided not to... |
There is a long discussion on dart repo for a similar topic, about having IMO it would be best to at least allow an option on the generator to choose between positional or named parameters. |
Looking at this example we can see that having named arguments for required fields insists to have default values for these fields, since they can not be null. class _PersonRequiredFields {
final String firstname;
final String lastname;
}
class PersonRequiredFields {
//generated realm object class constructors
PersonRequiredFields(String this.firstname, String this.lastname);
PersonRequiredFields.named({String this.firstname="", String this.lastname=""});// ->in this case
// the generator has to set the default values. Otherwise, the compiler will fail.
}
void main() {
PersonRequiredFields("Mark", "Parker");
PersonRequiredFields.named(firstname: "Mark"); // lastname becomes empty even though it is required
} If we change the realm model generator to generate For this reason if you prefer having named arguments we will suggest you to define your realm model as follow: class _PersonOptionalFields {
// you are able to set explicitly the desired default values
final String? firstname = "default name";
final String? lastname = "default name";
}
class PersonOptionalFields {
//generated realm object class constructor
PersonOptionalFields({String? this.firstname, String? this.lastname});
}
void main() {
PersonOptionalFields(firstname: "Mark", lastname: "Parker");
PersonOptionalFields(firstname: "Mark");
} In the sample above the generator will generate the exact constructor with named arguments that you prefer. But also allows you to set a specific default values. In case you need to have a setter generated for class _PersonOptionalFields {
late String? firstname = "default name";
late String? lastname = "default name";
}
void main() {
var person = PersonOptionalFields(firstname: "Mark", lastname: "Parker");
person.lastname = "something new";
} I hope this will answer your request for having named arguments constructor. |
Why not use named required params? class _PersonRequiredFields {
final String firstname;
final String lastname;
}
class PersonRequiredFields {
PersonRequiredFields.named({required this.firstname, required this.lastname});
} |
Before we add our feedback on this, can we just say we are incredibly grateful to the Realm team for launching the Flutter Realm package and we are so looking forward to this moving into GA. MongoDB Atlas is amazing and so is Flutter, so making them work seamless via Realm Sync is perfect. Thank you so much. Now for our feedback: Named or Positional Properties, or a combination of both
We request that the Realm team have the same approach as Google, and let the developer choose the approach they would like to make, as after all, this is all very subjective to the developer's approach when building applications. In our firm, we believe: => named properties:
=> required properties
Required Fields with 'default values'
Final thoughts Please let us really reiterate how grateful we are for the Realm Team's efforts - please keep them coming! - and we hope you will kindly consider our thoughts above. Thanks again! |
Thank you so much for giving us all these nice feedbacks. It seems to be important and more convenient for the developers to use named arguments for the required fields also. After having these reasoned feedbacks we can certainly consider providing named arguments for required fields in the constructors of generated models. We will discuss this option in the team. Thanks! |
Pleasure @desistefanova and we are really looking forward to your teams feedback. If you need any further info or thoughts please do reach out ;-) |
removed as incorrect issue |
I just wanted to create same issue about this topic but I found fortunately this. For me it's bezare that every time I have to reorder parameters in RealmObject creation, when I add or change fields. If all were named parameters there would not be such problems. |
a temp workaround we have used (which is not idea as its extra boilerplate that should not be needed) is creating a function with named properties which then returns an instance of the relevant RealmObject to then write to the DB... We are hoping Flutter Realm will support named properties for both required and non-required properties as in our feedback above soon. Hope this helps ;-) |
This is a must! Just moved from sqflite to Realm and object construction is a huge drawback. |
Migrated from Hive to Realm. With the case of not being able to use inheritance ( Having to use a workaround to make a workaround work isnt really friendly. Being able to optionally use named or unnamed parameters via annotations could be a great feature. We could enjoy the best of both worlds. |
Agree. We've received a fair amount of feedback that this would be a valuable customization point, so it is high on our backlog of tasks. While we can't commit to a timeframe for when this will ship, I do expect the team to look into it soon. |
This is the second most upvoted feature request by now, and much easier to achieve than #26, so we will make it opt-in that all arguments must be named. |
I'm also a fan of named arguments and wasn't happy with the positional arguments that Realm generates. I am new to Dart/Flutter and have tried something like this as a workaround until named arguments are supported officially. I appreciate it if someone could provide a suggestion or opinion on whether this is ok. @RealmModel()
class _RealmPerson {
late String firstName;
late String lastName;
}
class Person extends RealmPerson {
Person({
required String firstName,
required String lastName,
}) : super(
firstName,
lastName,
);
} |
Is there any ETA? This is painful. |
Amazing this is released, thank you so much! Is there a way to set the below 'globally' once rather than in 'each Realm model file'?
(from https://github.com/realm/realm-dart/releases/tag/2.2.0) |
Great job! By the way, need global config for all models. |
@dotjon0 I would just define: const config = GeneratorConfig(ctorStyle: CtorStyle.allNamed);
const realmModel = RealmModel.using(baseType: ObjectType.realmObject, generatorConfig: config); in a separate file, and import that where you define your model. |
Thanks @nielsenko, that helps. Would be best to set this globally if possible rather than having to import in each model. |
@dotjon0, @dfdgsdfg, and @jimisola. You need to import at least export 'package:realm/realm.dart';
import 'package:realm_common/realm_common.dart';
const _config = GeneratorConfig(ctorStyle: CtorStyle.allNamed);
const realmModel =
RealmModel.using(baseType: ObjectType.realmObject, generatorConfig: _config); and then import that instead in your models. Example import 'myrealm.dart';
part 'x.realm.dart';
@realmModel
class _Stuff {
late ObjectId _id;
} I hope this is convenient enough? |
Thanks @nielsenko appreciate it. Would be better in a global configuration file rather than having to remember to put this in - but then again, we are very grateful to have this functionality in any form. |
If you're worried about someone fat-fingering lowercase vs uppercase |
Hi @nirinchev would imagine a repo will either use the 'named approach' or 'positional approach' for Realm, not both. So setting it globally probably makes a ton of sense rather than setting it individually for each model. The additional import works, but again, its perhaps a workaround. Despite this, we are grateful for the support, so thank you. |
@dotjon0 In hindsight we should probably have had named arguments be the default. But history is history, and we are not going to break the existing behaviour for everyone now - I'm sorry. For those like you who wants named arguments all over it should be a fairly simple search-replace operation to switch the actual annotation, and add an extra import (or replace as suggested above). We can look into supporting some out-of-code json based global configuration later. |
Tried this but get lint error 'Annotation must be either a const variable reference or const constructor invocation.' |
@dotjon0 |
yep it is, odd the linter is throwing this up. |
@dotjon0 Not sure what is happening on your end. Here is a small sample project showing it works. |
@realmModel(ObjectType.embeddedObject) // <-- this is not valid dart You should define a separate const var, like: export 'package:realm/realm.dart';
import 'package:realm_common/realm_common.dart';
const _config = GeneratorConfig(ctorStyle: CtorStyle.allNamed);
const realmModel =
RealmModel.using(baseType: ObjectType.realmObject, generatorConfig: _config);
const embeddedModel =
RealmModel.using(baseType: ObjectType.embeddedObject, generatorConfig: _config); and use that like: @embeddedModel
class _Cat {
late String name;
} |
Thanks @nielsenko, thanks works, appreciated. FYI we took this from Realm Flutter docs at https://www.mongodb.com/docs/atlas/device-sdks/sdk/flutter/realm-database/model-data/data-types/#std-label-flutter-embedded-objects - see, where there is
|
@dotjon0 The docs are correct. The unary
// The generated `Address` class is an embedded object.
@RealmModel(ObjectType.embeddedObject)
class _Address {
// ..
} and @RealmModel()
class _Person {
// ..
} But you can also name those instance by storing them in const variables. That is what is happening with |
Thanks @nielsenko appreciated. Would it make sense to possibly have 2 x versions of @RealmModel() in Flutter Realm SDK? i.e. we could have
or for the named variation:
Or we could potentially (for the named):
|
For example, you have a datamodel class like this:
and this will generate a RealmObject class with this constructor:
Now, when you create a new
Hello
object, you need to know exactly the order of the arguments of the constructor:Hello(key, sth1, sth2, sth3, listA, listB);
THIS IS NOT FRIENDLY.
It should simply use named arguments in the constructor so order of the arguments does not matter & provide some flexibility (like skipping
listA
for default value and passinglistB
at the same time):The text was updated successfully, but these errors were encountered: