What is the similar syntax of Swift's try? on Flutter? - flutter

On Swift, we have try? when the error handling is just little of importance, and we just want to silence the whole ordeal and just "give me null if it fails".
Is there such thing in Flutter? I tried to find it, but I can only find the usual try ... catch clause on the documentation. I mean, sure I can make it like this:
dynamic result = null;
try { result = json.decode(response.body); } catch (e) { }
But I'm trying to find something more like this if it exists:
var result = try? json.decode(response.body);
This will have the added value of not having to manually type the variable type beforehand and let the lint/editor/compiler do that by simply using var (though in this specific case the type result might be dynamic).

There isn't a Dart language feature to do it. I'm not familiar with how try? works in Swift, but one potential problem for such a construct in Dart is that without specifying what you catch, you could catch logical errors (such as failed assertions).
If you don't mind an extra level of function calls, you could write a function to make it (arguably) a bit more convenient (and this also would give you control over what to catch):
T? doOrDoNot<T>(T Function() closure) {
try {
return closure();
} on Exception {
return null;
}
}
var result = doOrDoNot(() => json.decode(response.body));

Related

Swift 3 try to default value

I'm learning Swift and I'm testing the following code
var value: String;
do {
value = try getValue()
} catch {
value = "Default Value"
}
which can be shortened to
let value = (try? getValue()) ?? "Default Value"
It works but I feel I may be missing a more obvious solution.
Your solution is just great, and extremely elegant.
I presume we would like to avoid saying var in the first line and initializing the variable later. In general, the way to initialize a value immediately with a complex initializer is to use a define-and-call construct:
let value: String = {
do {
return try getValue()
} catch {
return "Default Value"
}
}()
And you would probably want to do that if the catch block was returning error information that you wanted to capture.
However, in this case, where you are disregarding the nature of the error, your expression is much more compact, and does precisely what you want done. try? will return an Optional, which will either be unwrapped if we succeed, or, if we fail, will return nil and cause the alternate value ("Default Value") to be used.

Handling errors in swift with try/catch

I come from a .NET background, where error handling can be as simple as wrapping a set of statements in a try-catch. For example:
try
{
statement1
statement2
}
catch (ex)
{
log(ex.Message)
}
I'm trying to add error handling in my Swift project, and all the articles I have read so far seem to indicate that error handling requires more work in Swift. In the example above, it seems I would need to know exactly which statement throws an error, and then add a "try" before it. Is it not possible to simply wrap a block of code in a try-catch, and inspect the error that gets thrown?
Nope, you can't just wrap a block of code with try-catch.
First of all, cause not every line of code could produce exceptions. Only functions marked as "throws" could produce exceptions.
For example, you have some function:
deserialise(json: JSON) -> MyObjectType throws
And let this functions throws exceptions of type MyErrorType
That's how you should use it:
....
do {
let deserialisedObject = try deserialise(jsonObject)
... // do whatever you want with deserialised object here
} catch let error as MyErrorType {
... // do whatever you want with error here
}
...
So, as you see, exceptions in swift is not the same thing as exceptions in C++(or other regular language) for .NET
You can use try catch in swift just like you do in .net with this little change in structure,
before that create a enum of exceptions which you want to catch like follows
//exceptions to catch, change as per your need
enum someActionError: Error {
case invalidSelection
case outOfStock
}
//use
do {
try statement1
} catch someActionError.invalidSelection {
print("Invalid Selection.")
} catch someActionError.outOfStock {
print("Out of Stock.")
}

Can I restrict the type that a function throws in Swift?

When calling a function in Swift 3 that throws, you have to be exhaustive in catching all possible errors, which often means you have an unnecessary extra catch {} at the end to handle errors that won't happen.
Is it possible to say throws MyErrorType so that the compiler can know you have indeed been exhaustive when you handle all cases from that enumeration?
There's no simple way to be type-safe with thrown errors. Consider this, if the compiler allowed you to specify throws MyErrorType, then it would also have to ensure within that function body that you're not trying a function that could potentially throw a different type outside of a do/catch block. (Well there is but it would add layers of unnecessary complexity). The Swift compiler can already be slow and get stuck in loops when inferring types, inferring Thrown types all the way up a chain of throwing functions could be a nightmare.
The running idea is that for most errors you're going to handle them in a small subset of ways anyhow.
That being said, there's no need for you to add extra catch let error as MyErrorType clauses, you can simply use a switch in a catch block like so:
do {
try something()
} catch let e {
switch e {
case let m as MyErrorType: handleMyError(m)
case let o as OtherErrorType: handleOther(o)
case is ThirdErrorType: print("error \(e)")
default: handleElse(e)
}
}
My suggestion for this problem is instead of throwing an error return a Result type in your function. It would be something like this.
enum MyCustomError: Error {
case genericError
}
func operationThatFails() -> Result<Response, MyCustomError> {
guard requiredConsition() else {
return .failure(.genericError)
}
return Response()
}
Then you can handle the error like this:
let result = operationThatFails()
switch result {
case .success(let value):
// handle success
case .failure(let error):
// handle error
}
This way your error is always type safe

Using guard keyword

I have encountered numerous situations where a coder have used the guard keyword. And then later, in a seemingly almost identical situation the same coder in the same code does not use the guard keyword. I am aware that this may be a stupid question, so please don't bash it. When should I use the guard keyword and where shouldn't I?
Here is an example (there are many more). This is part of a script that is requesting data form an API.
//Here I am using guard
guard let json = json else {
//Now I am not using guard
if let error = error {
completion(.Failure(error))
} else {
//Error handling
}
return
}
Why not use the:
if let var1 = var1 {
//Keep on going
} else {
//Don't crash
}
syntax all the time instead of the guard syntax? At first glance it even seems to have more functionality, but I am certain that does not have to be the case.
One great benefit of the guard statement is that you know that if the condition is not satisfied then the execution flow gets stopped.
This is important for several reasons
Unwrapping
You can define unwrapped values which don't need a new scope { ... } to be available
func next(num:Int?) -> Int? {
guard let num = num else { return nil }
return num + 1
}
Readability
When you read the code you know that if the guard condition is not satisfied then the following lines won't be executed.
Semantics
You know a guard statement is there to check conditions required for the following block of code.
But I can replace every guard with an if
Sure. We could also replace every while and for with a goto in some languages. And we could always replace recursion with iteration (and viceversa).
But this doesn't necessarily means it is always a good idea.
Despite we can implement some behaviours with more then one programming "tool", we should still use the one that better fits that specific scenario.

What is the _ underscore in front of Swift's catch block?

Swift 2.0 added do {} catch {} which can be used like so:
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(params, options: []);
} catch let jsonError as NSError {
print(jsonError);
}
but I've also seen in in my 2.0 converted classes the catch implemented with an underscore:
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(params, options: []);
} catch _ {
}
what makes it especially confusing is why not just provide nothing after catch which is perfectly valid code:
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(params, options: []);
} catch {
}
What is that underscore _, what can I do with it, how would I implement that in my own function signatures? In the previous Swift 1.2 declaration I didn't use the NSError so it makes sense that the conversion is throwing the error away but why use _?
You're asking a question about an automatic conversion. It's just a starting place! Apple doesn't know what you want to do, so they provide a completely minimal neutral catch-all catch block — it does nothing at all, but we compile because there's a catch-all. Obviously if you want to capture the error variable, you will delete the _ and capture the error variable. You might want to do much more, e.g. write a more focused catch block. It's up to you to build on the foundation you've been given.
If the variable declared before the catch block isn't actually used in the following block then Xcode will automatically convert this to an _ since it is not used. So in your example above, if jsonError wasn't actually used in the catch block, Xcode may automatically convert this to _. This isn't just for do {} catch {} but also things such as if let ... { }.
I think because it does this convert with other things too, like the if let ... {}, if they were to not put the _ in these places the code wouldn't actually work. Hence it does _ everywhere to be safe, even though in some places you may not actually need it.