How to create null safe, default value constructor with Syntactic sugar - dart

How do I create a null safe constructor with Syntactic sugar that would set a default value if the provided value is null?
class Person {
Person({
required this.name, //Idealy, adding (?? "friend") instead of "required" should've worked but doesn't.
required this.age,
});
String name;
int age;
greet() {
print("Hello $name");
}
}
So, I actually want something like this,
class Person {
Person({
this.name ?? "friend",
this.age ?? 0,
});
String name;
int age;
greet() {
print("Hello $name");
}
}
But, as you know this is not valid in dart. So, how actually, should I achieve this?

class Person {
Person({
String? name,
int? age,
}) : this.name = name ?? "friend",
this.age = age ?? 0;
String name;
int age;
void greet() {
print("Hello $name");
}
}

Constructor Optional Params
for selecting my proposal
select this as an answer (converted from comment with permission)

You can also use default values for your optional parameters:
class Person {
Person({
this.name = "friend",
this.age = 0,
});
String name;
int age;
greet() {
print("Hello $name");
}
}
The parameter is not required, and if you don't pass it, it gets the default value. If you do pass an argument, it must be non-null.

Related

Can required parameters in a Dart constructor be named?

I am working with some Dart code for a Flutter/Dart class I'm taking. I expected the following code to compile, but it did not:
class Person {
String? name;
int? age;
Person(this.name, this.age);
#override
String toString() {
return "name: $name\nage: $age";
}
}
void main() {
final person = Person(name: 'Joe', age: 30);
print(person);
}
When I made the constructor parameters optional, as below, it does compile:
class Person {
String? name;
int? age;
Person({this.name, this.age});
#override
String toString() {
return "name: $name\nage: $age";
}
}
void main() {
final person = Person(name: 'Joe', age: 30);
print(person);
}
I tried searching the Flutter dev docs for a reason why this is so, or a way to have required parameters with their names in a constructor, but I didn't find anything. I can certainly imagine cases where I would want required constructor parameters to have names.
My pubspec.yaml specifies the following:
environment: sdk: ">=2.12.0 <3.0.0"
Your first example uses what are called "positional parameters" in dart. You cannot call a positional parameter with a name label, which is why the first example does not compile.
The second example uses "named parameters". Any parameter defined within {} is considered a named parameter and must be called using a name label. As explained in the dart language tour, named parameters are optional unless they’re explicitly marked as required.
So simply add the required keyword before any named parameter you want to require.
class Person {
String? name;
int? age;
Person({required this.name, required this.age});
#override
String toString() {
return "name: $name\nage: $age";
}
}
void main() {
final person = Person(name: 'Joe', age: 30);
print(person);
}

How to pass null in a method?

class Foo {
final int? i;
Foo({this.i});
Foo copyWith({int? x}) {
return Foo(i: x ?? i);
}
}
void main() {
final foo = Foo(i: 0);
foo.copyWith(x: null);
print(foo.i); // prints `0` but should print `null`.
}
How can I actually pass null value to the method? In earlier Dart version copyWith() and copyWith(x: null) were two different things.
Note: I'm not looking for workarounds like making a new variable, like isNull and then deciding whether to pass null or not based on its value.
With simple copyWithwhit Dart null-safety you can't override value by null because if id is null return this.id. You need to override the value by null but not return with another value. It can solve in a few ways but I will give you the best example.
void main() {
final user = User(name: 'Dave', id: 110);
User copy = user.copyWith(id: null);
print(copy.toString()); // prints User(name: Dave, id: null).
}
class User {
User({required this.name, this.id});
final String name;
final int? id;
UserCopyWith get copyWith => _UserCopyWith(this);
#override
String toString() => 'User(name: $name, id: $id)';
}
abstract class UserCopyWith {
User call({
String name,
int? id,
});
}
class _UserCopyWith implements UserCopyWith {
_UserCopyWith(this.value);
final User value;
static const _undefined = Object();
#override
User call({
Object name = _undefined,
Object? id = _undefined,
}) {
return User(
name: name == _undefined ? value.name : name as String,
id: id == _undefined ? value.id : id as int?,
);
}
}

Dart null safety: the operand cannot be null, so the condition is always true

I am trying to double-check if the User object is successfully created, but Null saftey says
the operand cannot be null, so the condition is always true
What if in a scenario where the json data contains invalid type, in this case there might be some errors when creating the user object
class User {
String? name;
String? age;
User({name, age}) {
this.name = name;
this.age = age;
}
factory User.fromJson(dynamic json) {
return User(name: json['name'], age: json['age']);
}
}
void main() {
String data = '{name: "mike",age: "2"}';
User user = User.fromJson(data);
if (user != null) { // Warning: "The operand can't be null, so the condition is always true. Remove the condition."
}
}
Please advise, Thank you! :)
If something wrong is going on creating your User object from a JSON input, it will, in your case, throw an Exception which will crash the program if not catch.
So the variable user cannot be null in your case which is what the warning is telling you.
If you want to have some kind of User.tryFromJson which returns null in case of any problems, you could add something like this to you User class:
static User? tryFromJson(dynamic json) {
try {
return User.fromJson(json);
} catch (_) {
return null;
}
}
Also, some minor comments. Your User constructor does not make much sense since you could have written the following instead:
User({this.name, this.age});
Also, I would make both arguments required and prevent the nullable types. So something like this (also changed age to int):
class User {
String name;
int age;
User({
required this.name,
required this.age,
});
factory User.fromJson(dynamic json) => User(
name: json['name'] as String,
age: json['age'] as int,
);
static User? tryFromJson(dynamic json) {
try {
return User.fromJson(json);
} catch (_) {
return null;
}
}
}
void main() {
final data = '{name: "mike",age: 2}';
final user = User.fromJson(data);
}

how should I use assert in Dart?

I saw exmaple code something like:
class ModelBinding extends StatefulWidget {
ModelBinding({
Key key,
this.initialModel = const GalleryOptions(),
this.child,
}) : assert(initialModel != null),
super(key: key);
...
so I wrote something:
class Person {
String firstName;
Person({name}){
print(name);
}
}
class Employee extends Person {
Employee(String name) : assert(false), super(name: name);
}
main() {
var emp = new Employee('Jason');
}
No matter if it is assert(false) or assert(true), the result is same.
So what is the meaning of assert?
assert is used for debugging and it simply means the condition should be true to proceed. Let me explain:
class MyClass {
final int age;
MyClass({this.age});
void someMethod() {
// using `age` here
}
}
You might face issues in someMethod if age passed is null, so to make sure it isn't null, you use assert like:
class MyClass {
final int age;
MyClass({this.age}) : assert(age != null, "Make sure age isn't null");
void someMethod() {
// using `age` here
}
}

How to use this in a dart constructor with private variables

When I try to create a constructor in dart like Student(this._name) it doesn't work with private variables.
I have already tried using setters but it doesn't work either.
class Student{
var _id;
var _name;
Student(this.id, this.name);
void set id(int id) => _id = id;
void set name(String name) => _name = name;
}
This is not supported because it would expose private implementation to the outside.
If you'd rename var _id; to var _userId; you would break code that uses your class just by renaming a private field.
See instead the comment below my answer.
class Student{
var _id;
var _name;
Student({this._id, this._name}); // error
void set id(int id) => _id = id;
void set name(String name) => _name = name;
}
The alternative
class Student{
var _id;
var _name;
Student({int id, String name}) : _id = id, _name = name;
void set id(int id) => _id = id;
void set name(String name) => _name = name;
}
You can use this notation
class Student {
String _id;
String _name;
Student({required String id, required String name})
: _id = id,
_name = name;
}
Some of you maybe struggle if the class was inheritance, you just need add coma (,) after initialize your private.
Example
class Animal {
String _name;
int _age;
}
class Dog extends Animal {
String _race;
Dog(String name, int age, {String? race}) : _race = race ?? "Wild", super(name, age);
}
Hope this code can help you.
This notation is not valid because the variable is not private and its elements are just as accessible again.
DartLang says: AVOID wrapping fields in getters and setters just to be "safe".

Resources