Can required parameters in a Dart constructor be named? - dart

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);
}

Related

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?,
);
}
}

Using mixins for private fields or abstract methods Dart

I am experimenting with Dart mixins and noticed that
You can use private fields in mixins
Even abstract methods like abstract classes.
Imagine you have few abstract methods no need to create an abstract ad extend it, you can collect them inside a mixin and re-use it.
The discussion goes whether you like to have inheritance within your design
Here is a code snippet:
import 'package:flutter/cupertino.dart';
mixin Favourite {
bool _isFavourite = false;
bool get isFavourite;
}
class ProductProvider
with Favourite, ChangeNotifier
implements Comparable<ProductProvider> {
final String id;
final String title;
final String description;
final String imageUrl;
final double price;
ProductProvider({
required this.id,
required this.title,
required this.description,
required this.imageUrl,
required this.price,
});
ProductProvider.noPrice({
required this.id,
required this.title,
required this.description,
required this.imageUrl,
bool isFavourite = false,
}) : price = 0.0;
toggleFavourite() {
this._isFavourite = !this._isFavourite;
notifyListeners();
}
#override
bool get isFavourite => _isFavourite;
factory ProductProvider.fromJSON(Map<String, dynamic> json) {
return json['price'] != null
? ProductProvider(
id: json['id'],
title: json['title'],
description: json['description'],
imageUrl: json['imageUrl'],
price:
json['price'] is int ? json['price'].toDouble() : json['price'])
: ProductProvider.noPrice(
id: json['id'],
title: json['title'],
description: json['description'],
imageUrl: json['imageUrl'],
isFavourite: json['isFavourite'] ?? false,
);
}
#override
int compareTo(ProductProvider other) {
return (price - other.price).toInt();
}
}

i tried to run the code in dart pad, online platform

dart:
As you can see in this .dart code I am trying to print the list of id, there is a Dummy Data class which have a list of details of some product. There is a main function which call a instance (productIdList) of a class name Present.
class DummyData{
List<Product> dummyProduct = [
Product(
id: 'p1',
title: 'Red Shirt',
description: 'A red shirt - it is pretty red!',
price: 29.99,
imageUrl:
'https://cdn.pixabay.com/photo/2016/10/02/22/17/red-t-shirt-1710578_1280.jpg',
),
Product(
id: 'p2',
title: 'Trousers',
description: 'A nice pair of trousers.',
price: 59.99,
imageUrl:
'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Trousers%2C_dress_%28AM_1960.022-8%29.jpg/512px-Trousers%2C_dress_%28AM_1960.022-8%29.jpg',
),
Product(
id: 'p3',
title: 'Yellow Scarf',
description: 'Warm and cozy - exactly what you need for the winter.',
price: 19.99,
imageUrl: 'https://live.staticflickr.com/4043/4438260868_cc79b3369d_z.jpg',
),
Product(
id: 'p4',
title: 'A Pan',
description: 'Prepare any meal you want.',
price: 49.99,
imageUrl:
'https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Cast-Iron-Pan.jpg/1024px-Cast-Iron-Pan.jpg',
),
];
}
class Product{
final String id;
final String title;
final String description;
final double price;
final String imageUrl;
Product({this.id, this.description, this.imageUrl, this.price, this.title});
}
class Present extends DummyData{
void productIdList (){
print(dummyProduct.map((product) =>product.id).toList());
}
}
void main(){
Present obj = Present();
obj.productIdList;
}
The code above will not compile in the latest version of dart due to changes made to support null safety. Specifically the product class. You can fix in a few different ways.
The first approach would be to mark all of the constructor arguments in the Product class as required. This approach makes it so you have to pass in values for every constructor argument.
class Product {
final String id;
final String title;
final String description;
final double price;
final String imageUrl;
Product(
{required this.id,
required this.description,
required this.imageUrl,
required this.price,
required this.title});
}
The other approach would be to make the fields within the product class nullable. In this approach, you are not required to pass in a value for every constructor argument, but when you do not pass in a value the field will be assigned a null value.
class Product {
final String? id;
final String? title;
final String? description;
final double? price;
final String? imageUrl;
Product(
{this.id,
this.description,
this.imageUrl,
this.price,
this.title});
}

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 to create null safe, default value constructor with Syntactic sugar

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.

Resources