Flutter/Dart - Difference between obj!.property and obj?.property - dart

In Flutter/Dart their is the null safety feature. In my scenario, I have null safety ON and I am trying to get the property 'myDateTime' of my object MyDateTime . But the compiler produce the error:
The property 'myDateTime' can't be unconditionally accessed because the receiver can be 'null'.
Try making the access conditional (using '?.') or adding a null check to the target ('!').
which makes sense because the object can be null.
I tried both solution
MyDateTime!.myDateTime
and
MyDateTime?.myDateTime
and the both work fine but I don't understand the difference!! Can anyone elaborate?

MyDateTime!.myDateTime means: i know MyDateTime can never be null and it tries to access property myDateTime even if MyDateTime is null.
MyDateTime?.myDateTime means: i know MyDateTime can be null, so if it is, don't try to access property myDateTime
The first one returns an error if MyDateTime is null, the other one does not.

Related

Dart: Explain the "get" here [duplicate]

I'm learning Dart & Flutter, but I'm struggling with some basic programming issues like the use of getters:
GoogleSignInAccount get user => _user!;
What's the equivalent of the "get" method?
What does the ! at the end of a variable mean?
Thanks in advance!
That is a getter, in Java that code might look like:
public GoogleSignInAccount getGoogleUser(){ return this.user; }
Dart likes that code written more succinctly.
In Dart private class members are denoted via a _ in front of the variable/function name. So the variable that the getter is returning is a private variable, hence _user.
The ! at the end of the variable name has to do with Dart null safety. Throwing a ! at the end of the variable name is functionally the equivalent of saying assert _user != null; what it actually does is cast a nullable data type to its non-nullable equivalent.
In Dart, all data has two types, a nullable type, denoted by a ? at the end of the data type declaration, and a non nullable type.
The _user variable, it can be assumed from this code, is of the type GoogleSignInAccount? meaning that it can be null. However the getter wants to return a GoogleSignInAccount. Because there is no question mark on the end, the type the getter returns must NOT be null. So we put ! on the end of the _user variable to denote that we want to cast the nullable type to its not null form.
Note also that the name of this function is user and that in Dart you can have two functions of the same name if one is a getter and the other is a setter. To denote getter versus setter in a function declaration, you use the get and set keywords as you see above.
If you want to get a good idea of how getters and setters look in Dart, make a class with some variables. Make sure all of the variable names start with _ so that they are private, then right click in your IDE and tell it to generate some getters and setters for you. I believe both Android Studio and VSCode have the Generate option in their right click menu.
There are two things at play here:
1.
GoogleSignInAccount get user => _user!;
does the same as
GoogleSignInAccount user() {
return _user;
}
Where the first one is called a getter.
As a getter you can access it like a property. For example
myUser = userService.user;
With the function notation you access it like
myUser = userService.user();
Since you do not calculate anything but only expose that private member the getter notation is more succinct.
2.
Regarding the !:
Dart is null safe, which means types without a ? can't be null.
In your case the _user is a GoogleSignInAccount? which means it can be null. For example on startup when the user isn't signed in yet.
The getter GoogleSignInAccount get user has the type GoogleSignInAccount which means the compiler gives you an error when you try to assign null to it.
So
user can not be null.
_user could be null.
With the ! you promise to the compiler that you know that the _user is in no case null when the getter user is called.
Example:
This could be the case if the user is loaded right on startup while a progress indicator is shown. When the user is loaded you start the whole app and now you can access the user with user!. You are sure that the user is loaded.
If you somehow access the user before it's loaded (while it's still null) you get a runtime error.
Null safety just helps you to think about wheter a variable can be null and to avoid NullPointerExceptions.
The exclamation mark at the end of the private variable tells the compiler that the variable is not null and the user data returned by the getter must not be null.

The argument type 'TextStyle?' can't be assigned to the parameter type 'TextStyle'

I am getting this error...
code snippet that is throwing this error:
catalog.desc.text.textStyle(context.captionStyle).make(),
Your object context.captionStyle has the TextStyle? type, which means it can be null. The .textStyle() function only accepts TextStyle objects, hence the error.
You either have to make sure that context.captionStyle is not null before trying to pass it to .textStyle(), or assuring the compiler it will never be null by writing .textStyle(context.captionStyle!) (but you will still get an error if it becomes null somehow).

How to ensure user does not pass null variable to Flutter plugin?

Let's say, in Dart/Flutter you are designing a plugin API have a function like this:
static Future<void> startPlaying(Uint8List bytes) async {
_channel.invokeMethod('playBytes', bytes);
}
Would it be true to say that, thanks to the null-safety feature of Dart, we are not responsible in the event that the 'bytes' parameter is passed in as null by the plugin user (and thus causing a runtime crash) because in order to do so, they would have to explicitly unwrap a nullable variable, thereby promising that it is is not null.
OR... is there some other thing we should do such as throwing an exception?
With sound null safety, there is no way to call that method with null as argument.
With unsound null safety, which is what you get if not every library of your program is opted into null safety, it's technically possible to pass null as an argument (because a non-null safe library could be doing the calling, or could be passing null into other null safe code, which doesn't check because it assumes null safety.)
You can choose to check the value coming in, as an extra precaution.
The language makes that hard for you, because locally the code looks null safe.
Something like
if (bytes as dynamic == null) throw ArgumentError.notNull("bytes");
I personally wouldn't bother with that, unless there is a real risk of something going spectacularly wrong if null manages to get into the code.
It's documented as not allowing a null value, and most well-behaved code will respect that. Eventually, when all programs are soundly null safe, that check would just be dead code.
First:
if you mean the final user that use app on device, you should have a validation for input.
Second:
if you mean someone try your plugin to code the app.
you can add required keyword, the dart analysis give the user the error if don't pass bytes.
static Future<void> startPlaying({required Uint8List bytes}) async {
_channel.invokeMethod('playBytes', bytes);
}

Why is asigning a dynamic to a non-nullable not an error with sound null safety

In dart with sound null safety turned on it is entirely possible to do
dynamic myVar; // myVar assumes default value of null
String someString = myVar; // No warning by IDE.
As expected the above results in a run-time error since myVar is null and someString is non-nullable.
Is this a problem with the linter/IDE?
I did discover that I can enable pedantic linting that causes the IDE to show a warning when I try to implicitly cast dynamic to another type. Turning that on helps but I think the problem is that dynamic can be null without having to be explicitly defined as nullable.
In short we don't have
dynamic? myNullableVar;
My questions is: Is this a bug?
This "issue" bites you most commonly when you do something like
Map<String, dynamic> myData = jsonDecode(receivedResponseBody);
var name = myData['name'];
In the above example I expect the IDE to show a warning that I am trying to assign a potentially null value to a non-nullable variable. The IDE should require the user to add a null check.
If this is not a bug (in the IDE or in the linter), then why not?
Long story short: The implicit cast from dynamic to another type masks the issue with null assignments, and I expect the IDE to provide a warning.
EDIT: after note from # jamesdlin below
Specifically I am OK with the following where the Left-hand side of the assignment allows null values.
dynamic someVar;
String? myString = someVar;
Side note, I was hoping that the new dart typeDef feature would allow my to build something similar to Union type hints in Python. That would allow me to then get something like
typeDev JsonValueType = { int, String, float, bool };
And the result from jsonDecode would then be
Map<String, JsonValueType?>
Which explicitly includes Null and therefore the IDE would warn the user to add a null check.
My opinion: As long as you can assign any nullable type on the right of an assignment operator to a non-nullable type on the left, you don't have true sound null safety.
It's not a bug.
You can do:
dynamic x = "not an int";
int y = x;
and not get any compiler warnings. That's just how dynamic works, it turns off compiler ("static") type-checks and relies on run-time ("dynamic") checks instead. That's where the name comes from.
There is no reason to allow dynamic? because dynamic already allows the null value (and any other value). The dynamic type is inherently nullable, adding ? to it makes no difference, just as Null? is meaningless.
The Dart type system is statically null sound (mostly, the usual caveats around generics apply), but dynamic is a way to turn that type system off on request. Don't use dynamic unless you want that effect.

OLE automation: How to check if a variant references an automation object

I would like to know how can i determine, whether a variant is referencing an OLE automation object, or not.
I'm exporting some Excel graphs to Powerpoint.
I have this code:
var PptFile: Variant;
....
// PptFile _might_ be initialized:
PptFile:=pptApp.Presentations.Open(pptFilename);
// It depends on whether the export has items which need to be exported to
// Powerpoint or not
....
// I would like to determine if PptFile does reference an OLE automated object or not
PptFile.SaveAs(excelFileName+'.pptx');
I know, it could be done by placing the last line of the code (with saveAs) between try...except...end, but i don't feel that approach is good enough.
I was reading about VarIsEmpty, VarIsEmptyParam, Nothing, this question, but i'm not sure about this.
You should use VarIsClear for this test.
Indicates whether the specified variant has an undefined value.
VarIsClear returns true if the given variant's value is undefined. The
value can be undefined for any of several reasons:
The Variant may have had its value set to Unassigned.
The Variant's value may be an interface type that has been set to nil (Delphi) or NULL (C++).
The Variant may be a custom variant that returns true from its IsClear method.
In all other cases, the function result is false.
Note: Do not confuse an unassigned variant with a Null variant. A Null variant is still assigned, but has the value Null. Unlike
unassigned variants, Null variants can be used in expressions and can
be converted to other types of variants.
However, I question whether or not it is needed. How could it be that PptFile was not assigned? That can only happen if the call to pptApp.Presentations.Open() fails, and that would raise an exception. Or am I mis-understanding this? I cannot at the present see any scenario in which you could reach the call to PptFile.SaveAs() for which PptFile had not been assigned.

Resources