I found out that I can assign data to a property using set or a method.
class Human {
String name, address;
set rewriteName(String name) {
this.name = name;
}
set rewriteAddress(String address) {
this.address = address;
}
void rewrite(String name, String address) {
this.name = name;
this.address = address;
}
String introduction() => "Name is $name. I live in $address";
Human(this.name, this.address);
}
I tried to assign some data using both way, and method looks more efficient than using setter, since its only need just one call to change everything:
Human human = Human('stacker', 'baghdad');
// using method
human.rewrite('overflow', 'new york');
// using setter
human.rewriteName = "Hooman";
human.rewriteAddress = "jakarta";
my question is why using a setter instead of method?
Typically, the targets of getters and setters are made private so they're not directly accessible from outside of the file or library.
class Business {
String name, _address;
double lat, long;
bool coordsCalculated = false;
Map propertyRecords = {};
get address {
return _address;
}
set address(String address) {
if (address == _address) return; // Nothing changed;
_address = address;
// API call to calculate lat/log
APICall(onSuccess: (data) {
lat = data.lat;
long = data.long;
coordsCalculated = true;
});
}
void rewrite(String name, String address) {
this.name = name;
this.address = address;
}
String summary() {
if (coordsCalculated) return "Business name is $name, here's a link to the map!";
return "Business name is $name, at $_address.";
}
Human(this.name, String address) {
this.address = address;
}
}
The user of the class feels like they're using a normal property, but it does other silent things.
Methods can do this too, yes, but this can feel cleaner.
Importantly, getters and setters cannot be asynchronous which definitely can give methods an advantage, but there are plenty of valid uses.
Getters and setters are also easier to read, when being used. Less parentheses are always a good thing.
You certainly don't need to always use them, or use them when they do nothing but set the variable, but they can be nice.
In one of my Widgets, I have a getter that looks something like
FileState get fileState => FileUploaderKey.currentState!. widget.file.state;
It's so much easier to read this way. It gets the current state of the file, always, whereas
FileState fileState = FileUploaderKey.currentState!.widget.file.state;
Only saves the current state, but doesn't change with it.
It's basically about what the usage looks like, a method call with a parameter vs. what looks like an assignment to a property. From Dart.dev's Effective Dart: Design
DO use setters for operations that conceptually change properties.
Linter rule: use_setters_to_change_properties
Deciding between a setter versus a method is similar to deciding between a getter versus a method. In both cases, the operation should be “field-like”.
For a setter, “field-like” means:
The operation takes a single argument and does not produce a result value.
The operation changes some state in the object.
The operation is idempotent. Calling the same setter twice with the same value should do nothing the second time as far as the caller is concerned. Internally, maybe you’ve got some cache invalidation or logging going on. That’s fine. But from the caller’s perspective, it appears that the second call does nothing.
In your example you're comparing a method that changes two properties with two separate setters. You'd use the method if it's essential that the two properties both be updated at the same time, as a single conceptual operation. If the properties are independent (and otherwise meet the criteria above), you might use setters instead (if you need to do something when they're set; otherwise, simple data fields might make more sense).
Related
I'm using Firestore database and i want to update some fields from a document.
var updateFields = {
"completedByUid": authRepo.getUID(),
"completed": currentTime,
};
return await docRef.update(updateFields);
Instead of typing the properyName manually how can i get the name directly from an object Object, and by this avoiding typing it incorrectly or outdated.
Let's say i have an object like:
#JsonSerializable()
class OrderModel {
String? completedByUid;
String? completed;
}
and i want to get the serialization name something like:
var updateFields = {
OrderModel.completedByUid: authRepo.getUID(),
or
var updateFields = {
order.completedByUid.properyName: authRepo.getUID(),
Normally this would be a use for reflection but that might be overkill.
I think the design pattern you could use is a constant that you use to both set and read the values, like so:
const String ORDER_MODEL_COMPLETED_BY_UID_PROPERTY = "completedByUid";
This doesn't exactly guarantee a match if, for example, some existing data is present and may have a name mismatch.
For an answer based on reflection, see this answer.
https://dart.dev/guides/language/effective-dart/design#avoid-public-late-final-fields-without-initializers
AVOID public late final fields without initializers.
Unlike other final fields, a late final field without an initializer
does define a setter. If that field is public, then the setter is
public. This is rarely what you want. Fields are usually marked late
so that they can be initialized internally at some point in the
instance’s lifetime, often inside the constructor body.
Unless you do want users to call the setter, it’s better to pick one
of the following solutions:
Don’t use late. Use late, but initialize the late field at its
declaration. Use late, but make the late field private and define a
public getter for it.
The above explanation is abstract and I have no concrete image of what kind of risk this rule envisions.
I would be grateful if you could give me a hint as to how to think.
The risk is that you accidental try to assign a value twice, which will result in an error.
late final String a;
void someMethod() {
a = "a";
a = "b";
}
The above code compiles perfectly fine and is valid code because of the late but leads to a crash.
As for the suggested solutions
Don’t use late.
Use late, but initialize the late field at its declaration.
final String a = "b";
// or
late final String a = "b";
void someMethod() {
a = "a";
a = "b";
}
This makes it that the above code doesn't even compile, making it sure that the crash doesn't happen.
Late modifier means a variable's value is not known during declaration but will definitely get initialized and not null when it's accessed.
When we declare a variable as final, it means that it will only assigned once. Therefore, all the final fields has to be initialized either at declaration or inside the class constructor.
Given above facts, for one to declare a late final variable as public would probably a mistake. One should either pass the value to final field as class constructor parameter, or declare the late final field as private and initialize it internally.
Let see the example why late final field should not be made public
class Coffee {
late final String temperature; // public field as there's no prefix underscore, e.g. _temperature
// based on description from the guide, a setter will be created automatically for public late final
set temperature(String val) => temperature = val;
// again, do you think you would want above?
// as it's final field, it means it should only be initialized once!
// The creation of the setter for late final (public field) does not make too much sense
// Therefore usage late final as public field is rarely what you will want
}
Not sure if it's true, but I think this advice is to enforce better architecture. If field is final then you can set it value only once and almost always you need to initialize it from within the class it belongs to.
But if setter for final field is public then people might attempt to set it value from elsewhere AFTER it is already initialized, and this will lead to an error.
UPD: two sections above there is this advice, that basically summarizes my point:
Objects shouldn’t generally expose more state than they need to.
...and setter is not needed after final field has been initialized.
I have lots of getters for localizations (they are coming from the json file for example) such as:
String get start {
return localizedValues[locale.languageCode]!['start']!;
}
String get hours {
return localizedValues[locale.languageCode]!['hours']!;
}
String get minutes {
return localizedValues[locale.languageCode]!['minutes']!;
}
String get seconds {
return localizedValues[locale.languageCode]!['seconds']!;
}
So I want to compound them since they use some common codes (I tried to create final someWord = commonCode; but It did not work, so I wanted to ask)
Now, If I want to reach them, I use myClass.of(context).start for example. So, in the end, I will reach using the same way but in the class which is above, I will not do any duplication If you help me. So, I need your help to avoid duplication.
I would recommend using a data class to hold localisation data instead of just a Map, or using a package such as i10n to do the translations for you.
There are a couple of ways you can shorten this code. For starters, you can extract localizedValues[locale.languageCode]! to its own getter, like this:
Map<String, String> get localeValues => localizedValues[locale.languageCode]!;
Then all your methods become a bit shorter:
String get seconds {
return localeValues['seconds']!;
}
Additionally, you can shorten your getters by removing the function body and using an arrow function instead, like I did above for the localeValues:
String get seconds => localeValues['seconds']!;
Do this for all your getters, and your code is now shorter.
You can use this method, and shorten the code:
String getTime(String languageCode, String time) {
return localizedValues[languageCode]![time]!;
}
getTime("1529", "seconds");
getTime("859", "mitutes");
getTime("9632", "hours");
How can I use the setter of a private instance variable from the default constructor in Dart?
Given the example class:
class A {
String name;
int _age;
int get age => _age;
set age(age) {
_age = age ?? 0;
}
A(this.name, this._age);
}
How can I use this constructor to go through the set age() function? Is there away aside from using a factory? I'd like to do something like this
A(this.name, newAge): age = newAge;
But I get an error forcing me to only set instance variables from the constructor, which has me just duplicating the setter:
A(this.name, newAge): _age = newAge ?? 0;
Am I missing something or is this just not possible with dart?
The initialization list of a constructor can be used only to initialize members (or call base class constructors). (Additionally, when the initialization list is executed, this isn't valid yet, so you can't access any members.)
If you want to do other kinds of initialization work, you can do it in the constructor body instead, at which point the object is considered to be sufficiently constructed for this to be valid:
A(this.name, int newAge) {
age = newAge;
}
Also see:
Difference between assigning the values in parameter list and initialiser list, which explains why this becomes valid only for the later stages of object initialization.
https://stackoverflow.com/a/64548861/ for various differences between the different ways to initialize members and for an example where the different ways matter.
Is it bad practice to change my getter method like version 2 in my class.
Version 1:
public String getMyValue(){
return this.myValue
}
Version 2:
public String getMyValue(){
if(this.myValue == null || this.myValue.isEmpty()){
this.myValue = "N/A";
}
return this.myValue;
}
I think it is actually quite a bad practice if your getter methods change the internal state of the object.
To achieve the same I would suggest just returning the "N/A".
Generally speaking this internal field might be used in other places (internally) for which you don't need to use the getter method. So in the end, the call to foo.getMyValue() could actually change the behaviour of foo.
Alternatively, the translation from null to "N/A" could be done in the setter, i.e. the internal value could be set to "N/A" if null is passed.
A general remark:
I would only add states such as "N/A" if they are expected by some API or other instance relying on your code. If that is not the case you should rely on the standard null types that are available to you in your programming language.
In my opinion, unless you are doing lazy-loading (which you are not in that case), getters should not change the value. So I would either:
Put the change in the setter
public void setMyValue(String value) {
if(value == null || value.isEmpty()){
this.myValue = "N/A";
} else {
this.myValue = value;
}
}
Or make the getter return a default value if value not set properly:
public String getMyValue() {
if(this.myvalue == null || this.myvalue.isEmpty()){
return "N/A";
}
return this.myValue;
}
In the case of lazy-loading, where I would say that changing your members in a getter is fine, you would do something like:
public String getMyValue() {
if (this.myvalue == null) {
this.myvalue = loadMyValue();
}
return this.myValue;
}
No. You're doing two things here. Getting and setting.
Yes. It's a bad practice.
Why?
When the value is set (in a constructor or setter method), it should be validated, not when a getter method is called. Creating a private validate* method for this is also a good idea.
private boolean validateThisValue(String a) {
return this.myValue != null && !this.myValue.isEmpty();
}
public void setThisValue(String a) {
if (validateThisValue(a)) {
this.myValue = a;
}
else {
// do something else
// in this example will be
this.myValue = "N/A";
}
}
And, in the getter method, never ever change the state of the object. I have worked on some projects, and the getter often must be made const: "this method cannot change internal state".
At least, if you do not want to complicate things, in the getter method, you should return "N/A" rather than change internal state and set myValue to "N/A".
I usually define a specific getter.
Never alter original getter:
public String getMyValue(){
return this.myValue
}
And create a specific getter:
public String getMyValueFormatted(){
if(this.myvalue == null || this.myvalue.isEmpty()){
return "N/A";
}else{
return this.myValue;
}
}
I think it's better to initialize this.myValue = "N/A". And subsequent calls to setMyValue should modify the this.myValue according to your business conditions.
The getMyValue shouldn't modify in any way this.myValue. If your needs are to return a certain value, you should return that value (like "N/A") and not alter this.myValue . Getters must not modify member's value.
I would change better the setter method so, if the value is null or empty, the N/A is assigned to the attribute. So, if you use the attribute in other methods inside the class (v.g. toString()) you will have the intended value there.
Alternatively, change the setter method to launch an exception when the value being set is not right, so the programmer is forced to improve its handling prior to setting the value.
Other than that, it is ok.
I do feel this is a bad practice unless and until you explain the reason why it is so necessary for you modify the object inside the getter method instead of doing it inside the setter method.
Do you feel this cannot be done for some reason? Could you please elaborate?
Do what ever you like. After all getters and setters are just another public methods. You could use any other names.
But if you use frameworks like Spring, you are bound to use those standard names and you should never put your custom codes inside them.
absolutely yes, it's a bad pratice.
Imagine you communicate accross network with a third party (remoting, COM, ...), this will increase the round-trip and then hit application performance.
A setter could modify as part of validation, but a getter should return the value and let the validation be done by the caller. If you do validate, then how should be documented.
This actually highly depends on the contract you want to enforce with your get()-method. According to design-by-contract conventions the caller has to make sure that the preconditions are met (which means doing a validation in a setter method often is actually bad design) and the callee (I do not know if that's the correct english term for that, i.e., the called one) makes sure that the post conditions are met.
If you define your contract so that the get()-method is not allowed to change the object then you are breaking your own contract. Think about implementing a method like
public isValid() {
return (this.myvalue == null || this.myvalue.isEmpty());
}
Advantage of this approach is that you do not have to check wether the return of your get() is "N/A" or something else. This also can be called before calling set() to validate that you do not insert illegal values into your object.
If you want to set a default value you should do that during initialization.
State changes in getters should be a hanging offence. It means that client code must be careful about the order in which it accesses getters and setters and to do this it must have knowledge of the implementation. You should be able to call the getters in any order and still get the same results. A related problem occurs when the setter modifies the incoming value depending on the current state of the object.
You can use some value holder for this purpose. Like Optional class in guava library.