Catch an 'as' typecast exception in flutter - swift

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

Related

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

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 - !

"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 - !

Swift: Error ignores try statement

In my code I'm deserialising some XML using the SWXMLHash library. Its .value() method has the throws keyword in its declaration, as do any custom deserialise functions.
I have the following line of code:
let myValue : UInt8 = try? xml["Root"]["ValueNode"].value()
Since the library doesn't include a deserialiser for UInt8, I've defined my own:
extension UInt8: XMLElementDeserializable {
public static func deserialize(_ element: XMLElement) throws -> UInt8 {
return UInt8(element.text)!
}
}
This works when the node has a value. However, when the node doesn't exist or is nil, an error occurs on the following line:
return UInt8(element.text)! // Fatal error: Unexpectedly found nil while unwrapping an Optional value
This is supposed to happen, obviously. What I don't understand is why this error is not being caught by my try? statement and returning nil instead of throwing that error.
Can anyone help?
Not all errors can be caught in Swift. If you mark a function using the throws keyword it indicates that the function might throw a recoverable error. However, your custom implementation doesn't actually throw any errors. Only errors thrown from functions marked with the throws keyword and thrown using the code throw Error can be caught by a do-catch block.
try? is a way to convert a throwable function's return value to an optional. If the function would throw an error, the value after the try? will be nil, otherwise it will be an optional value.
When you use the !, you specifically tell the compiler that you know what you are doing and if the operation on which you used the ! fails, your app shouldn't fail gracefully.
You'll need to change your deserialize method to handle the optional unwrapping gracefully or throw and error.
extension UInt8: XMLElementDeserializable {
public static func deserialize(_ element: XMLElement) throws -> UInt8 {
if let val = UInt8(element.text) {
return val
} else {
throw NSError(domain: "Couldn't deserialize value to UInt8", code: 1)
}
}
}
return UInt8(element.text)!
There's no try in this line. Therefore, no errors are going to be thrown here. If UInt8 can't convert the string it's given, it just returns nil. And then, of course, your ! turns that nil into a crash.
Instead of that, do something like this instead:
guard let retVal = UInt8(element.text) else { throw SomeError }
return retVal
In general: When there's a way to do something using !, and another way to do the same thing without using !, go for the second one unless you've got a really good reason.

How to avoid returning an optional after throwing an exception?

I'm writing a utility function which takes a parameter and always returns a valid non-nil result (notice the returned value is not optional because the possible parameters are all actually hardcoded and valid, so I know the function cannot fail):
func myFunction(param: String) -> NonTrivialObject {...}
Now, during development I want to experiment with possible parameters and, should I make a mistake, I want the function to throw an exception and just crash. I don't want or need to throw Swift errors or catch them, I want to hard-crash and fix the parameter immediately. In Objective C I would just use NSParameterAssert() or do something along these lines:
guard let validatedParam = param where param != nil else {
NSException(...).raise()
return nil
}
// do the actual work and return a non-optional result
However, I cannot return nil because the result is not an optional. Is there a way to somehow tell the compiler that it doesn't need to bother returning anything from the function after an exception is thrown? Or am I doomed to litter my code with unwrapping optionals or try! statements or to return a dummy object just to make the compiler pleased?
You can use Swift assert(_:_file:line:) function as follows
assert(some condition, "Message to display if condition is false (optional)" )
If the condition is verified the app will continue running, otherwise it will terminate
An optional may contain nil, but Swift syntax forces you to safely deal with it using the ? syntax to indicate to the compiler you understand the behavior and will handle it safely.
You can define the function to be a throwing function:
func foo(param: String) throws -> NonTrivialObject {
guard param != nil else {
throw SomeErrorEnum.NilFound
}
doStuff(...)
}
The error enum needs to conform to the ErrorType protocol. The function call is now able to catch errors like this:
do {
try foo(param)
} catch SomeErrorEnum.NilFound {
print("Found nil")
}
In this way the function returns a non-optional but can also throw errors. For more information see: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html

How do I handle runtime error in swift?

I do not know how do I handle runtime error in swift. I need to check for a parsing error and do something about it. Can anyone help me please?
I have code something like this:
var:SomeObject = parse("some string")
I need to handle any generic error that occurs in runtime.
Thanks!
If the function is yours, then in case of a failure, you can make that function return a nil value.
That way your line of code
var anObj:SomeObject = parse("some string")
would become something like this
var:SomeObject? = parse("some string")
Notice the ? sign. It means that the value in it is Optional. In simple words, it could be some actual value, or it could be nil.
After this function, you should perform a check like
If anObj != nil
{
//do something
}
else
{
//the parse didn't go right, handle the erorr here.
}
Swift 2 adds additional safety to your error checking. You use the throws keyword to specify which functions and methods could throw an error. Then you have the do, try, and catch keywords for when you call something that could throw:
// 1
enum ParseError: ErrorType {
case InvalidValue
}
// 2
func parseWithError(value:String) throws {
if value.count > 0 {
// yeaaa!
} else {
// 3
throw ParseError.InvalidValue
}
}
func parse(value:String) {
// 4
do {
try parseWithError(value)
} catch {
print("Could not parse! :[")
return
}
}
There are a few things to highlight here:
To create an error to throw, simply create an enum that derives from ErrorType.
You need to use the throws keyword to mark any function that can throw an error.
This throws an error, which will be caught in section 4.
Instead of try blocks, which might be familiar from other languages, you wrap any code that can throw an error in a do block. Then, you add the try keyword to each function call that could throw an error.
For more read here or this is the official documentation of Error Handling