How come Flutter doesn't accept null checking within an 'if' statement [duplicate] - flutter

I'm upgrading a personal package that is based on the Flutter framework. I noticed here in the Flutter Text widget source code that there is a null check:
if (textSpan != null) {
properties.add(textSpan!.toDiagnosticsNode(name: 'textSpan', style: DiagnosticsTreeStyle.transition));
}
However, textSpan! is still using the ! operator. Shouldn't textSpan be promoted to a non-nullable type without having to use the ! operator? However, trying to remove the operator gives the following error:
An expression whose value can be 'null' must be null-checked before it can be dereferenced.
Try checking that the value isn't 'null' before dereferencing it.
Here is a self-contained example:
class MyClass {
String? _myString;
String get myString {
if (_myString == null) {
return '';
}
return _myString; // <-- error here
}
}
I get a compile-time error:
Error: A value of type 'String?' can't be returned from function 'myString' because it has a return type of 'String'.
Or if I try to get _mySting.length I get the following error:
The property 'length' can't be unconditionally accessed because the receiver can be 'null'.
I thought doing the null check would promote _myString to a non-nullable type. Why doesn't it?
My question was solved on GitHub so I'm posting an answer below.

Dart engineer Erik Ernst says on GitHub:
Type promotion is only applicable to local variables. ... Promotion of an instance variable is not sound, because it could be overridden by a getter that runs a computation and returns a different object each time it is invoked. Cf. dart-lang/language#1188 for discussions about a mechanism which is similar to type promotion but based on dynamic checks, with some links to related discussions.
So local type promotion works:
String myMethod(String? myString) {
if (myString == null) {
return '';
}
return myString;
}
But instance variables don't promote. For that you need to manually tell Dart that you are sure that the instance variable isn't null in this case by using the ! operator:
class MyClass {
String? _myString;
String myMethod() {
if (_myString == null) {
return '';
}
return _myString!;
}
}

The Error:
Let's say, this is your code and you're doing a null check on the instance variable and still seeing an error:
class Foo {
int? x;
double toDouble() {
if (x != null) return x.toDouble(); // <-- Error
return -1;
}
}
The method 'toDouble' can't be unconditionally invoked because the receiver can be 'null'.
The error you see in code like this is because Getters are not promoted to their non-nullable counterparts. Let's talk about the reason why.
Reason of the Error:
Let's say, there's a class Bar which extends Foo and overrides x field and implemented like this:
class Bar extends Foo {
#override
int? get x => (++_count).isOdd ? 1 : null;
int _count = 0;
}
Now, if you do
Bar().toDouble();
You would have run into a runtime null error, which is why getters type promotion is prohibited.
Solutions:
We need to cast away nullability from int?. There are generally 3 ways to do this.
Use local variable (Recommended)
double toDouble() {
final x = this.x; // <-- Use a local variable
if (x != null) return x.toDouble();
return -1;
}
Use ?. with ??
double toDouble() {
return x?.toDouble() ?? -1; // Provide a default value
}
Use null-assertion operator (!)
You should only use this solution when you're 100% sure that the variable (x) will never be null.
double toDouble() {
return x!.toDouble(); // Null assertion operator
}

style: Theme.of(context).textTheme.headline5!.copyWith(
style: Theme.of(context).textTheme.headline5!.copyWith(
color: Colors.white
Try making the call conditional using ? or a null safety checker - !

Related

How can I fix the error instance of class name?

Can someone tell me how I can fix the error instance of class name?
return placeName ?? '';
you just need to handle if its null
Type String? means it has to have a string or null in variable of this type So the solution is to change type to String and add required keyword to named parameter in constructor.
Try this might work...
//'A value of type 'String?' can't be returned from the method 'toString' because it has a return type of 'String'
showing this because you've to handle null exception there. do placeNmae?
or
if (placeName != null) {
return placeName;
//2
} else {
codeExceptionsomething();
}
}

void function not printing because cant return value but when i make string or int function it print null or return value at the end automatically

New to dart, take following code as example, //void function doesnt work and int/string function either returns null that is printed or value return which is automatically printed as can be seen in the output.
class Microphones{
String? name;
String? color;
int? model;
String printEverything(){
print(name);
return " ";
}
int? printint(){
print(model);
}
}
void main() {
var mic1=Microphones();
print(mic1.name);
mic1.name="Yeti";
mic1.color="black";
mic1.model=26;
print(mic1.name);
print(mic1.color);
print(mic1.model);
print(mic1.printEverything());
print(mic1.printint());
}
output:
null
Yeti
black
26
Yeti
26
null
i highly appreciate your replies/help in this regard.
All methods in Dart retuns null by default if you are not returning anything (either by having an empty return in methods specified to return void or not having any return at all in methods returning void or a nullable type like int?).
But return-type in the method signature specifies how the caller of the method should see the value. And here we have void which is described in the Dart language tour as:
A special type that indicates a value that’s never used.
https://dart.dev/guides/language/language-tour#a-basic-dart-program
So we specify void to signal to the user of our method, that the returned value should never be used. And the Dart analyzer and compiler will then try very hard to make sure you are not ending up using the returned value typed void.
Advanced section for the curious
But that does not mean it is impossible to use a returned value specified to be void by the method signature:
void someMethod() {
void someVoidVariable = 'Hey, I am a String!';
return someVoidVariable;
}
void someOtherMethod() => 'Hey, I am also a String!';
void main() {
print(someMethod() as String); // Hey, I am a String!
print(someOtherMethod() as String); // Hey, I am also a String!
}
In the first example, we force Dart to see our String as void. That is completely fine since all types can be seen as void. We are then allowed to return this void value since someMethod() is suppose to return void.
The reason for this forcing is that Dart would complain about (which makes sense because what we are doing is very much stupid and should never be in a real program):
void someMethod() {
return 'Hey, I am a String!';
// ERROR: A value of type 'String' can't be returned from the function
// 'someMethod' because it has a return type of 'void'.
}
Or this since we can't cast to void using as:
void someMethod() {
return 'Hey, I am a String!' as void; // ERROR: Expected a type name.
}
We are then casting that void back to a String to let Dart allow us to use the returned value in print() (since Dart otherwise would prevent us from trying to use the void typed value).
In the second example, I show the one of the reasons for why things are working like they does. In Dart, we can write these two method which are going to do the exact same (note I changed the return type to String for this example):
String someOtherMethod() {
return 'Hey, I am also a String!';
}
String someOtherMethod() => 'Hey, I am also a String!';
So the second way is a shorthand for if we just want to execute a single statement and return its value.
But what about:
void someOtherMethod() => 'Hey, I am also a String!';
If we followed the traditional rules, this would not be allowed since we cannot return a String since we have typed void. But sometimes, we also want to use this simple syntax to just execute a method and don't want to care about what that method would end up returning.
E.g. this:
final someList = <String>[];
void removeStringFromList(String string) => someList.remove(string);
Where the remove method on List is actually returning a bool which indicate if the element was inside the list.
So Dart ignores this problem when we use the => by just casting the result to void in this case. So in our last example, the returned bool is actually returned to the caller of removeStringFromList but because its type has been cast to void, the caller of removeStringFromList is prevented (in a lot of ways) from using the value.

"The operator can’t be unconditionally invoked because the receiver can be null" error after migrating to Dart null-safety

I'm upgrading a personal package that is based on the Flutter framework. I noticed here in the Flutter Text widget source code that there is a null check:
if (textSpan != null) {
properties.add(textSpan!.toDiagnosticsNode(name: 'textSpan', style: DiagnosticsTreeStyle.transition));
}
However, textSpan! is still using the ! operator. Shouldn't textSpan be promoted to a non-nullable type without having to use the ! operator? However, trying to remove the operator gives the following error:
An expression whose value can be 'null' must be null-checked before it can be dereferenced.
Try checking that the value isn't 'null' before dereferencing it.
Here is a self-contained example:
class MyClass {
String? _myString;
String get myString {
if (_myString == null) {
return '';
}
return _myString; // <-- error here
}
}
I get a compile-time error:
Error: A value of type 'String?' can't be returned from function 'myString' because it has a return type of 'String'.
Or if I try to get _mySting.length I get the following error:
The property 'length' can't be unconditionally accessed because the receiver can be 'null'.
I thought doing the null check would promote _myString to a non-nullable type. Why doesn't it?
My question was solved on GitHub so I'm posting an answer below.
Dart engineer Erik Ernst says on GitHub:
Type promotion is only applicable to local variables. ... Promotion of an instance variable is not sound, because it could be overridden by a getter that runs a computation and returns a different object each time it is invoked. Cf. dart-lang/language#1188 for discussions about a mechanism which is similar to type promotion but based on dynamic checks, with some links to related discussions.
So local type promotion works:
String myMethod(String? myString) {
if (myString == null) {
return '';
}
return myString;
}
But instance variables don't promote. For that you need to manually tell Dart that you are sure that the instance variable isn't null in this case by using the ! operator:
class MyClass {
String? _myString;
String myMethod() {
if (_myString == null) {
return '';
}
return _myString!;
}
}
The Error:
Let's say, this is your code and you're doing a null check on the instance variable and still seeing an error:
class Foo {
int? x;
double toDouble() {
if (x != null) return x.toDouble(); // <-- Error
return -1;
}
}
The method 'toDouble' can't be unconditionally invoked because the receiver can be 'null'.
The error you see in code like this is because Getters are not promoted to their non-nullable counterparts. Let's talk about the reason why.
Reason of the Error:
Let's say, there's a class Bar which extends Foo and overrides x field and implemented like this:
class Bar extends Foo {
#override
int? get x => (++_count).isOdd ? 1 : null;
int _count = 0;
}
Now, if you do
Bar().toDouble();
You would have run into a runtime null error, which is why getters type promotion is prohibited.
Solutions:
We need to cast away nullability from int?. There are generally 3 ways to do this.
Use local variable (Recommended)
double toDouble() {
final x = this.x; // <-- Use a local variable
if (x != null) return x.toDouble();
return -1;
}
Use ?. with ??
double toDouble() {
return x?.toDouble() ?? -1; // Provide a default value
}
Use null-assertion operator (!)
You should only use this solution when you're 100% sure that the variable (x) will never be null.
double toDouble() {
return x!.toDouble(); // Null assertion operator
}
style: Theme.of(context).textTheme.headline5!.copyWith(
style: Theme.of(context).textTheme.headline5!.copyWith(
color: Colors.white
Try making the call conditional using ? or a null safety checker - !

Catch an 'as' typecast exception in flutter

how can i catch an 'as' typecast exception in flutter. For example this causes an expection as the cast wasn't successful.
final success = mapJson['success'] as String;
In Swift we can use a guard let or an if let statement. Is there something similar for flutter/dart?
Extending the Answer of #Christopher you can even catch specific exceptions using the on block and execute exception specific code:
try {
// ...
} on SomeException catch(e) {
//Handle exception of type SomeException
print(e)
} catch(e) {
//Handle all other exceptions
print(e)
} finally {
// code that should always execute; irrespective of the exception
}
You can use a try-catch block to catch all exceptions in nearly any situation. You can read more about them here and from many other places online.
Example usage:
void main() {
int x = 3;
var posVar;
try{
posVar = x as String;
}
catch(e) {
print(e);
}
print(posVar);
}
This print outs
TypeError: 3: type 'JSInt' is not a subtype of type 'String'
null
on DartPad and will be different in a real environment. The code in the try block throws an exception that is caught and can be handled in the catch block.
The Swift guard-let and if-let are used to avoid null values (nil in Swift) and either assign the non-null value to a variable, or execute the else branch (which must contain a control-flow operation in the guard case).
Dart has other patterns for doing the same thing, based on type promotion. Here I'd do:
final success = mapJson['success'];
if (success is String) {
... success has type `String` here!
}
With the (at time of writing yet upcoming) Null Safety feature's improved type promotion, you can even write:
final success = mapJson['success'];
if (success is! String) return; // or throw or another control flow operation.
... success has type `String` here!
You should not make the code throw and then catch the error (it's not an Exception, it's an Error, and you should not catch and handle errors). The "don't use try/catch for control flow" rule from other languages also applies to Dart.
Instead do a test before the cast, and most likely you won't need the cast because the type check promotes.
Make use of Null-aware operator to avoid unwanted Null and crash.
this is short an alternative to try catch (which is more powerful).
Null-aware operator works like guard let or if let in swift.
??
Use ?? when you want to evaluate and return an expression IFF another expression resolves to null.
exp ?? otherExp
is similar to
((x) => x == null ? otherExp : x)(exp)
??=
Use ??= when you want to assign a value to an object IFF that object is null. Otherwise, return the object.
obj ??= value
is similar to
((x) => x == null ? obj = value : x)(obj)
?.
Use ?. when you want to call a method/getter on an object IFF that object is not null (otherwise, return null).
obj?.method()
is similar to
((x) => x == null ? null : x.method())(obj)
You can chain ?. calls, for example:
obj?.child?.child?.getter
If obj, or child1, or child2 are null, the entire expression returns null. Otherwise, getter is called and returned.
Ref: http://blog.sethladd.com/2015/07/null-aware-operators-in-dart.html
Also Check Soundness in dart
https://dart.dev/guides/language/type-system

Is Dart's Optional operator an enum, similar to Swift's?

I want to know what the difference is between Dart Optional class Dart ?. operator and Swift optionals. I understand that they all help avoid null references and that Dart has the Optional.dart class which seems to operate similarly to the ?.
Swift Optional is just an enum that BASICALLY (I'm stressing basically) determines if it is null(empty)or not. How does Dart's optional differ from Swift's? Can they be used similarly? In Dart what is the difference between Optional class and using the ?. operator?
Dart Classes
Swift Optionals
Dart Optional Class
Dart:
void main() {
NewClass nc = NewClass();
nc.p = 3;
print(nc.p); //prints 3
nc = null;
if(nc?.num != null) {
nc.num = 4; //never entered
}
print(nc.num); // Uncaught exception:Cannot read property
// 'get$num' of null
}
class NewClass {
var p;
int num;
}
Dart does not have an Optional class that's part of the language. The package that you linked to is a third-party package.
Dart has null-aware operators (such as ??, ??=, ?., ...?). They work specifically for null values; there are no special types involved.
Swift has optional types; it lets you declare that the type of a variable is Int?, which means it might be null or it might be an Int.
In Dart, any variable can store a null pointer. Note that there is ongoing work to add non-nullable types to Dart, so this should eventually change.