How to initialize a variable in the constructor? - flutter

I'm learning how to use clean architecture and I just started with the repository (appwrite) and used a singleton pattern. Now I want my AuthService class to take a repository and continue.
However I have a problem in this class:
import 'package:appwrite/appwrite.dart';
import 'package:mandi/infrastructure/repositories/appwrite_service.dart';
class AuthService {
final AppwriteService _appwriteService;
AuthService({AppwriteService appwriteService})
: _appwriteService = appwriteService;
Future<void> register(
String email,
String password,
String firstName,
String lastName,
) async {
final Account account = Account(_appwriteService.client);
account.create(
userId: ID.unique(),
email: email,
password: password,
name: '$firstName $lastName',
);
}
}
The constructor gives an error at 'appwriteService' because "The parameter 'appwriteService' can't have a value of 'null' because of its type, but the implicit default value is 'null'.
Try adding either an explicit non-'null' default value or the 'required' modifier.".
I just read on this platform that after the ':' comes the initializer field, however, the compiler still complains about it being possibly null.
I don't know how to solve this.

Please try the below code bloc :
if you want name constructor you have to give required
AuthService({ required AppwriteService appwriteService})
: _appwriteService = appwriteService;
Without named constuctor you can use like :
AuthService(AppwriteService appwriteService)
: _appwriteService = appwriteService;

Related

Why does it keep saying initialize variable?

Below is the code I wrote. I need to initialize a variable called verificationID for later use. But I keep getting a red squiggly line with the text -
Final variable verificationID must be initialized
Non-nullable instance field vdi must be initialized.
Is this not how you initialize - final [datatype] [name]
I am brand new to flutter and could use any help!
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
enum NumberVerification {
SHOW_MOBILE_FORM_STATE,
SHOW_OTP_FORM_STATE,
}
class LoginScreen extends StatefulWidget {
final String verificationID;
String vdi;
#override
_LoginScreenState createState() => _LoginScreenState();
}
All variables in Dart are getting the value null if nothing else are specified. This is a problem in your case since both verificationID and vdi are specified as non-nullable types (no ? after the type name). So Dart complains about this problem.
Another problem is your final variable which also should be provided a value since this is a read-only variable which can only be assigned a value when initialized.
You therefore need to do:
Change the types to allow null.
Or, provide default value other than null.
Or, make a constructor of your class which gives values to your variables. These values can come from parameters to the constructor.
Because flutter and dart language are null safety. It means you should initialize your variables, and there will be no error regarding this in runtime. So when you write dart codes you must initialize them as follows:
1- In some cases you can init value directly as follows:
final String verificationID = 'value';
2- Or you can get the value from constructor of class.
final String verificationID;
LoginScreen(this.verificationID);
3- And also, you can declare that you will initialize the value later. This way you guarantee that you will initialize the value, so you should use it wisely.
late String verificationID;
verificationID = 'value';
4- Lastly, you may declare a value as nullable. This way, you don't need to initialize the variable directly.
String? verificationID;

Can this class be reconfigured to accept named parameters in Flutter?

Background code
I have a class called Result that I'm using to pass on some error codes and error messages to an error screen.
class Result<T>{
Result._();
factory Result.loading(T msg) = LoadingState<T>;
factory Result.success(T value) = SuccessState<T>;
factory Result.error(T title, T msg, T errorcode) = ErrorState<T>;
}
class ErrorState<T> extends Result<T> {
final T title;
final T msg;
final T errorcode;
ErrorState(this.title, this.msg, this.errorcode) : super._();
//final T msg;
}
This class is called as follows:
return Result.error("Error","Status code not 200", 1);
My problem
Functionally it all works great.
The problem is I see myself in the future having to refer back to my class Result code to remember what each field represents which may become even more problematic if I want to add in more fields down the line
I'd rather convert this so that the fields are named
My question
Can this class be converted so that it is called like this (with a name describing the parameter):
return Result.error(title:"Error", msg:"Status code not 200", errorcode:1);
If you want to change Result.error to accept named parameters without breaking existing call sites, you can't do that. Parameters can be either positional or named, but not both.
If you're okay with breaking existing call sites, then you can just make them required named parameters. Since you're using redirecting constructors, you either will need to:
Change the signature of the redirectee constructor (in your case, ErrorState) to exactly match that of Result.error:
factory Result.error(
{required T title, required T msg, required T errorcode}) = ErrorState<T>;
...
ErrorState({required this.title, required this.msg, required this.errorcode})
: super._();
Or change Result.error to be a non-redirecting constructor:
factory Result.error(
{required T title, required T msg, required T errorcode}) {
return ErrorState<T>(title, msg, errorcode);
}
(If you do want to avoid breaking existing callers, you could add a separate named constructor (or static method) that uses named parameters, and you could optionally deprecate the old constructor.)
As an aside, it does not make sense that Result and ErrorState are generic classes. Do you really expect title and msg to not be Strings? Does it really make sense for the type of title, msg, and errorcode to be the same? (With the example you've shown, you'll end up with Result<Object>, which defeats the point of using a generic class.)

Flutter i18n shortcut

I'm trying to make a function that get my i18n string by passing variable.
String getStringLanguage(context, String key) {
dynamic translation = AppLocalizations.of(context);
String tmp = key.toString();
return translation.key;
}
but I have this error
Class 'AppLocalizationsFr' has no instance getter 'key'.
Receiver: Instance of 'AppLocalizationsFr'
Tried calling: key
I understand why I have this error, but is it possible to force flutter to use my key variable, instead of searching the key constant ?
this is a small part of my AppLocalizations class
abstract class AppLocalizations {
String get email;
}
Try...
1- Import the library
import 'package:intl/intl.dart';
2- Use the function to get the value
Intl.message(translation.key)

Dart Class with ":" vs Dart Class without [duplicate]

I have a class that I am creating that looks like this:
class Movie {
final String title, posterPath, overview;
Movie(this.title, this.posterPath, this.overview);
Movie.fromJson(Map json) {
title = json["title"];
posterPath = json["poster_path"];
overview = json['overview';
}
}
I am getting a warning that says that "The final variables 'overview', 'posterPath', & '1' more must be initialized. There are also warnings around each variable saying 'title' can't be used as a setter because it is final.
When I write the constructor using this syntax, the warnings go away:
Movie.fromJson(Map json)
: title = json["title"],
posterPath = json["poster_path"],
overview = json['overview'];
What exactly is going on here?
Dart objects must be fully initialized before anyone gets a reference to the new object. Since the body of a constructor can access this, the object needs to be initialized before entering the constructor body.
To do that, generative Dart constructors have an initializer list, looking similiar to C++, where you can initialize fields, including final fields, but you cannot access the object itself yet. The syntax:
Movie.fromJson(Map json)
: title = json["title"],
posterPath = json["poster_path"],
overview = json['overview'];
uses an initializer list (the list of assignments after the :) to initialize the final instance variables title, posterPath and overview.
The first constructor uses an "initializing formal" this.title to directly put the parameter into the field.
The constructor
Movie(this.title, this.posterPath, this.overview);
is effectively a shorthand for:
Movie(String title, String posterPath, String overview)
: this.title = title, this.posterPath = posterPath, this.overview = overview;
Your constructor can combine all of these and a body:
Movie(this.title, this.posterPath, String overview)
: this.overview = overview ?? "Default Overview!" {
if (title == null) throw ArgumentError.notNull("title");
}
(A const constructor cannot have a body, but it can have an initializer list with some restrictions on the allowed expressions to ensure that they can be evaluated at compile-time).
Dart separates properties initialization from the constructor body.
A constructor has 3 parts :
the name/parameters definition
properties initialization/super call/asserts
A body, similar to a function immediately run on construction
Both the initialization and body parts are optional.
final variables must be initialized on the first 2 parts. They cannot be initialized inside the body.
A full constructor will look like the following :
MyClass(int value)
: assert(value > 0),
property = value,
super();
{
print("Hello World");
}
The main purpose of this initializer part is for body-less constructors which allows const constructors, a dart specific feature. See How does the const constructor actually work? for more details on these.
I just found some documentation around this, & it seams that the second version with the : is what's called the "initializer list" which allows you to initialize instance variables before the constructor body runs.
There is more detail around this in the documentation here.

Flutter required keyword

I don't really understand how required works. For example I've seen this code:
class Test{
final String x;
Test({
required this.x
});
factory Test.initial(){
return Test(x: "");
}
}
But what should required do here? Seems like it makes an optional parameter a non optional parameter.
Update
As of Dart 2.12, the required keyword replaces the #required meta annotation. For detailed info look into the official FAQ. The following answer has been updated to reflect both this and null safety.
Parameters required by default
The parameters of a class constructor or function are required by default.
class Test {
final String x;
Test(this.x);
}
You're not allowed to do this:
final value = Test();
// 1 positional argument(s) expected, but 0 found.
You must do this:
final value = Test('hello');
Optional named parameters
If you surround a parameter with curly braces, though, in addition to becoming a named parameter, it also becomes optional.
Since it's optional, the property must either be nullable like this:
class Test {
final String? x;
Test({this.x});
}
Or it has to have a default value like this:
class Test {
final String? x;
Test({this.x = ''});
}
So now this is ok:
final value = Test();
And so is this:
final value = Test(x: 'hello');
Required named parameters
Sometimes you don't want to allow a parameter to be null and there is no natural default variable. In that case you can add the required keyword in front of the parameter name:
class Test {
final String x;
Test({required this.x});
}
This is not ok anymore:
final value = Test();
// The named parameter 'x' is required, but there's no corresponding argument.
But this is still fine:
final value = Test(x: 'hello');
Dart 2.12 (null safety):
Beginning with Dart 2.12, the #required annotation is now replaced by the required keyword. You should mark your field required if it is mandatory for others to pass some value to it.
For example:
class Foo {
final int a; // Mandatory? Use 'required'
final int b; // Not mandatory? Don't use 'required'
Foo({
required this.a, // Marked 'required'
this.b = 1,
});
}
Usage:
Foo(); // Error: 'a' is required
Foo(a: 0); // Good
Foo(a: 0, b: 1); // Good
#required is an annotation that will create a warning for you to remember that the named parameter is necessary for the class to work as expected.
It will not create compile errors, at least for what I know.
#required bounds you to pass #required marked arguments while creating object of Class. For example, while showing a dialog, you'd mark context as required since, you cannot show dialog without having a valid context. But, you should not overuse it.
Short answer: Named parameters are optional by default in Dart. We prefer them to positional params for ease of use. In this case, the named parameters also might be expected to hold some value all the time (non-nullable) - from initialization itself. Hence, the double effort.
He could use default value initialization of the parameters instead of 'required', if the values were compile-time constants, and that doesn't seem to be the case here.
Positional parameters can be required or optional, which we pass in order when calling. The following is an example of required positional parameters' usage:
class Object{
String name;
int value;
Object(this.name, this.value=100); //auto type inference
}
final one = Object("Name here", 50); // All parameters are needed to call.
Named parameters are another type of optional parameters. Flutter APIs use named parameters and in our UI code, it is preferred to use named parameters instead of positional parameters. Reason being readability and clarity when reading code or calling the constructors later on at several parts of the code. You would have seen this as the case with all Widgets, Styles. For if it were to be positional it would be difficult to keep track of them upon calling with the sheer amount of methods that would be in use, and dynamic type inference could also be at work.
void display({required String name, int value1, int value2=100}) {...;} //named params
display(value1: 50, name: "Calculated name");
NOTE:
If exists, required positional parameters have to come first. Either named or optional positional params can follow(NOT BOTH).
String say(String from, String msg, [String? device]) { //req. pos params and opt pos params.
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
Remove
required
in constructor.
Instead write
final String? x;
So, it becomes as:
class Test{
final String? x;
Test({
this.x
});
factory Test.initial(){
return Test(x: "");
}
}