Xcode debugger highlighting wrong line when I throw an exception - swift

I'm trying to put a very simple unitTest-Like function together for teaching Swift, when we're not quite ready for the full XCTest framework.
I've put together this code:
enum TestFailure : Error {
case testEqFailure(_ msg: String)
}
func testEq<E:Equatable>(_ actual: E, _ expected: E ) throws {
if actual == expected { return }
print("Test failed")
print("Actual Result : \(actual)")
print("Expected Result: \(expected)")
throw TestFailure.testEqFailure("Test Values were not equal")
}
try testEq(1,1)
try testEq(7,8)
It "works" just fine (as shown by the output):
Test failed
Actual Result : 7
Expected Result: 8
Swift/ErrorType.swift:200: Fatal error: Error raised at top level: vPlay.TestFailure.testEqFailure("Test Values were not equal")
2021-11-01 10:36:52.050106-0400 vPlay[49261:2400984] Swift/ErrorType.swift:200: Fatal error: Error raised at top level: vPlay.TestFailure.testEqFailure("Test Values were not equal")
but when I run it, Xcode is highlighting the wrong source line:
What am I missing? (BTW, this is being used in the top level code of a command line program to keep things simple and focus on the actual coding)

Try calling the function with a do catch instead
try testEq(1,1)
do {
try testEq(7,8)
} catch {
print(error)
}
The error I get in playground is "An error was thrown and was not caught:" but not pointing to the first function call rather the second function call.
When you have a block of code that contains a method which can potentially throw an error you need to call the function with a do catch statement.
When the throwing method fails and raises the error the execution will go into the catch block and be handled according to what you dictate within the catch block.
The first function call is not failing because it doesn't throw an error but if it is for whatever IDE your using then try a do catch on that call as well.

If you want to teach a sudo assert test with a throwing function then you will have to teach error handling also or swift will fail when it has to handle the error being thrown.
You could eliminate the throwing and enum error if you want to simplify this for a beginner but still get the point across.
func testEq<E:Equatable>(_ actual: E, _ expected: E ) {
if actual == expected { return }
print("Test failed")
print("Actual Result : \(actual)")
print("Expected Result: \(expected)")
}
testEq(1,1)
testEq(7,8)
This will print what you want to see, actual and expected with the print test failed along side it to simulate a failure.

Related

Catching an error from a non-throwing method

Swift
Integers in Swift are ok. They cannot be infinite like Doubles, thought. They have a limit.
Surpassing that limit will cause a crash.
Exhibit A
Int(10000000000000000000)
error: integer literal '10000000000000000000' overflows when stored into 'Int'
Exhibit B
Int(pow(Double(1000000000), Double(10)))
Fatal error: Double value cannot be converted to Int because the result would be greater than Int.max
I naively thought to myself, "Hey, this is a fatal error. Can I catch the error with a do, catch block?"
Nope
Exhibit C
do {
Int(pow(Double(1000000000), Double(10)))
} catch {
print("safety net")
}
print("good?")
warning: 'catch' block is unreachable because no errors are thrown in 'do' block
Fatal error: Double value cannot be converted to Int because the result would be greater than Int.max
Oh, yeah. That's right! I forgot to add try
Nope
Exhibit D
do {
try Int(pow(Double(1000000000), Double(10)))
} catch {
print("safety net")
}
print("good?")
warning: no calls to throwing functions occur within 'try' expression
warning: 'catch' block is unreachable because no errors are thrown in 'do' block
Fatal error: Double value cannot be converted to Int because the result would be greater than Int.max
What is going on?
Can anyone explain this to me? I would really like to be able to catch an error like this.
Thank you so much, this would be a huge help!
You can use the init(exactly:) constructor, it will not throw an error but it will return nil if the value is to large
guard let value = Int(exactly: pow(Double(1000000000), Double(10))) else {
//error handling
}

How can I throw and handle error based on data in Swift?

Code :
enum PwdError : Error
{
case obvious;
}
func chkPwd(_ pwd : String) throws -> Bool
{
if(pwd == "pwd")
{
throw PwdError.obvious;
}
return true;
}
print(chkPwd("pwd"));
The output from REPL.it :
Swift version 5.0.1 (swift-5.0.1-RELEASE)
 swiftc -o main main.swift
main.swift:10:5: error: expected expression
throws PwdError.obvious;
^
main.swift:16:7: error: call can throw but is not marked with 'try'
print(chkPwd("pwd"));
^~~~~~~~~~~~~
main.swift:16:7: note: did you mean to use 'try'?
print(chkPwd("pwd"));
^
try
main.swift:16:7: note: did you mean to handle error as optional value?
print(chkPwd("pwd"));
^
try?
main.swift:16:7: note: did you mean to disable error propagation?
print(chkPwd("pwd"));
^
try!
compiler exit status 1
In the above code, I'm trying to handle an error, but all I'm getting are errors. I'm learning Swift, so I'm new to it. I do work in Java as of now, so if someone explains in terms of Java, that would be awesome for me.
You have to invoke the function using try keyword
do {
try chkPwd("pwd")
}
catch {
print(error) // prints obvious
}

Single try meaning in Swift

I looked for this article, but it does not cover my case.
If i understand correct, we can use try either in do..catch.. statement or in a function that can throw.
But sometimes i see something like:
let jsonData = try jsonEncoder.encode(employee1)
Where jsonData is not optional. What is meaning of this? What if try sttement fail? Why value is not optional? Can someone explain? Thanks.
In addition to the cases you mentioned, you can call try at
top-level code. Here is a simple self-contained example:
// main.swift:
enum MyError : Error {
case failed
}
func foo() throws -> Int {
throw MyError.failed
}
defer { print("Good bye.") }
let x = try foo()
print(x)
You can compile and run this as a Xcode "Command Line Project"
or directly from the command line:
$ swiftc main.swift
$ ./main
Good bye.
Fatal error: Error raised at top level: main.MyError.failed: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.74.1/src/swift/stdlib/public/core/ErrorType.swift, line 187
Illegal instruction: 4
The failed try in the top-level code causes the program to
terminate with an error message. Deferred statement (if present) will be executed however.
This is slightly different from using a forced try! statement,
which causes the program to abort as well, but immediately, without executing deferred statements. (This can be relevant if deferred
statements are used to clean-up resources, e.g. remove temporary files).
The error message originates from ErrorType.swift, line 187:
/// Invoked by the compiler when code at top level throws an uncaught error.
#_inlineable // FIXME(sil-serialize-all)
#_silgen_name("swift_errorInMain")
public func _errorInMain(_ error: Error) {
fatalError("Error raised at top level: \(String(reflecting: error))")
}
(also observed in Non Exhaustive List When Handling Errors Inside a Class Function in Swift).
Apparently the top-level code behaves as if embedded in a
do-catch block:
do {
func foo() throws -> Int {
throw NSError(domain: "foo", code: 0, userInfo: nil)
}
defer { print("Good bye.") }
let x = try foo()
} catch {
fatalError("Error raised at top level: \(String(reflecting: error))")
}
A function call marked with try like the one you posted, as you stated, must be located inside a function marked with the keyword throws or a do/catch statement or it will cause a compile error.
On a side note if you want to call a throwing function outside a do/catch or another throwing function you can use try? before your function call to get an optional result that will be nil if something is thrown. There is also the try! variant that assumes nothing will be thrown returning a non-optional result, but if something is thrown the app will crash.

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.")
}

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