1

In C# or Java, usually parsing a numeric string throws a format exception. However, the following code did not catch the error. What is wrong?

func getInt(_ data:String)->Int
{
    do
    {
        return try Int(data)!
    }
    catch
    {
        return -1;
    }
}

var a = "x123"
var b:Int = getInt(a)
print("Result: " + b)
Damn Vegetables
  • 8,055
  • 11
  • 49
  • 98
  • 2
    `!` == forced unwrap == "I *want* the program to crash if the value is nil" – Martin R Oct 21 '17 at 18:00
  • Compare https://stackoverflow.com/q/37222811/2976878 & https://stackoverflow.com/q/34628999/2976878 – Hamish Oct 21 '17 at 18:11
  • _"the following code did not catch the error"_ It also produces two compiler warnings that strongly suggest what you're doing wrong. It is strange that this initializer doesn't throw, however, given how exceptions are used elsewhere. – jscs Oct 21 '17 at 18:15
  • 1
    Why would you want `-1` to indicate a failed parse, when `nil` does exactly that, ***without*** the possibility of being misinterpreted as a (successful) parsing of `"-1"`? – Alexander Oct 21 '17 at 20:17
  • As I wrote in another comment, that method is not the real one. In the real method, a valid value can never be a negative. – Damn Vegetables Oct 22 '17 at 02:25

3 Answers3

4

Your approach is completely wrong. The Int initialiser returns an optional Int, so here's how you use it:

if let converted = Int (data) {
    // Yes, it was converted
} else {
    // No, conversion failed. 
}

or alternatively

guard let converted = Int (data) else {
    // Conversion failed
    return
}

// Continue using "converted". 

The try won't catch any exceptions, because no exceptions are thrown. Int (data) returns an optional Int, in other words either an Int, or nil. It never throws. There are no exceptions to catch. Having a function getInt that only does what Int() does anyway is just adding totally unneeded complexity. Creating a function getInt that throws an exception is even worse.

gnasher729
  • 47,695
  • 5
  • 65
  • 91
  • That method was just for illustration purpose. The real method does more and returns an int. I tried that sample code in a Playground, it showed a red popup with some kind of bad something exception at the conversion line, so I assumed it threw an exception, just like other languages such as C#. I clicked the Int() document, but it showed about the whole int class, so I could not easily figure out what exceptions it threw or not. – Damn Vegetables Oct 21 '17 at 19:19
  • It is so bad that Apple shows how to create an Int initializer that throws https://developer.apple.com/documentation/swift/error – Leo Dabus Oct 21 '17 at 19:53
2

Do not explicitly unwrap Int(data)! but use the nil returned to your advantage:

func getInt(_ data: String) -> Int {
    return Int(data) ?? -1
}

As an aside, in the grander scheme of things, the optionals exist so that you don't have to use "magic numbers" such as -1 to represent a missing value. If possible, rewrite the code that calls this method to accept a nil value when the string can't be parsed.

John Dough
  • 275
  • 1
  • 7
1

In Swift only methods which can throw can catch. The Int initializer does not throw

The Swift pattern are optionals

func getInt(_ data:String) -> Int?
{
    return Int(data)
}

let a = "x123"
if let b = getInt(a) {
    print("Result: \(b)")
} else {
    print("No result")
}

Or you can return a non-optional and handle the optional error with the nil coalescing operator

func getInt(_ data:String) -> Int
{
    return Int(data) ?? -1
}

let a = "x123"
let b = getInt(a)
print("Result: \(b)")

Or make your method can throw

enum MyError : Error {
   case conversionError
}

func getInt(_ data:String) throws -> Int
{
    guard let result = Int(data) else { throw MyError.conversionError }
    return result

}

let a = "x123"
do { 
    let b = try getInt(a)
    print("Result: \(b)")
} catch MyError.conversionError {
    print("Could not convert the string '\(a)' to integer")
} 

Please read the section about Optionals in the Swift Language Guide

vadian
  • 232,468
  • 27
  • 273
  • 287