Data structure for flagging input error

I am writing a tool which accepts certain set of inputs, including some files, parses them, does error checking and if there are no errors then proceeds to do the actual work.

There are about 20 predefined errors with specific error strings in specification for which the tool does input verification.

I can do these error checks without using any data structure (I am new to swift land). But I am intrigued by use of enums and exploring if they make sense in this case.

So, I am planning to write something as follows:

enum ErrorCheck {
     case incorrectFilePathProvided (code: Int, description: String)
     case inputFileIsMissingVersionNumber (code: Int, description: String)
     ....
}

let errorIncorrectFilePathProvided = ErrorCheck.inputFileNotProvided(1, "User has provided incorrect input file")
....

static func validateInputParams(param1: String, param2: NSDictionary) -> NSArray {
     var result: NSMutableArray = []
     if !param1.hasPrefix("/Application") {
        result.add([ErrorCheck.errorIncorrectInputFilePathProvided.code : ErrorCheck.errorIncorrectInputFilePathProvided.description])
     }
     
     if !param2["specificKey"] {
             result.add([ErrorCheck.errorIncorrectInputFilePathProvided.code : ErrorCheck.errorIncorrectInputFilePathProvided.description])
      }
} 

Does this approach makes sense or is there more swifty way to do this?

Without knowing more about what you're doing, what you have more or less makes sense to me. Some minor thoughts though:

  1. Is there a reason you're using the Foundation NS- types instead of the Swift equivalents?
  2. You could have ErrorCheck conform to Error, though that would only be useful if
    1. you expect to throw ErrorChecks at some point or
    2. had other APIs that expect and use Error or
    3. you have ErrorCheck implement Error.localizedDescription, which would let you switch over ErrorCheck and express your error cases in user-readable language.

@mattcurtis : Thanks. I am an Objective-C dev. So, sometimes by mistake use NS objects. That should not exist in my code. Thanks for suggestions.

1 Like

It depends on how you want to handle the errors downstream. Use of NSArray and code snipped suggest almost nothing, so any clarification on the overall goal would be helpful to provide more concrete solutions that fit better.

As for now, few options I can suggest in general.

Use Swift Error

Every error in Swift is expressed by adopting the protocol Error. It doesn’t requiers anything to be adopted, but enables language mechanics. Your type seems missing it and relies on ObjC code, so starting there I’d suggest to update it:

enum ValidationError: Error {
    case incorrectFilePath
    case missingVersionNumber
}

In case you’d like to bridge this to ObjC, you can also adopt CustomNSError and provide additional values, like domain, code, userInfo. If you will work with the error in ObjC code I highly recommend doing that, as Swift automatic bridging not always works well.

In case you just want to provide some user friendly description, you can add a computed property and switch over cases.

Throw single error

If validation at any given point should stop further execution, use throwing mechanism:

static func validateInputParams(param1: String, param2: NSDictionary) throws -> [ValidatedParams] {
    if !param1.hasPrefix("/Application") {
        throw ValidationError.incorrectFilePath
    }
}

Collect errors

If you want to have information about all errors that has occurred during validation, collect them. I like to create compound error type in such cases.

struct CompoundValidationError: Error {
   let errors: [ValidationError]
}

Then you can choose to either throw error as well at the end.

1 Like