Should I use enums or class hierarchy for errors in swift? -


in swift 2 type conforms errortype protocol can thrown , caught. me, makes sense have common error hierarchy , re-use in multiple places. but, apple documentation seems push developers using enums handling errors.

for example, hierarchy let me catch , process common validationerror without knowing it's exact sub-type. allow different parts of application extend validationerror.

myapperror     validationerror         invalidpatherror         wrongfiletypeerror 

mixing different styles of defining errors not idea. so, should model error handling around class hierarchies or enums?

tl;dr

enums shorter, faster write, easier understand potential errors, , compiler make sure catch of errors.

the full story

errortype empty protocol (there hidden properties _code : int , _domain : string apple takes care of that).

i quote swift programming guide (link)

swift enumerations particularly suited modeling group of related error conditions, associated values allowing additional information nature of error communicated.

to elaborate on that, enums allow express can go wrong. when doing error handling, have specific conditions can fail (swift pushes in direction optionals , type safety). because errors distinct cases shouldn't need many layers of inheritance (if add details answer please). errors can represented enums. using large inheritance hierarchy overly complicated.

say want every error have message can displayed user. instead of subclass use protocol.

protocol myapperror : errortype {     var message: string { } } 

taking given example little further represent validationerror enum (as there many validation errors).

enum validationerror : myapperror {     case invalidpatherror (string)     case wrongfiletypeerror (expectedfiletype: string)      var message: string {         switch self {         case .invalidpatherror(let invalidpath):             return "\(invalidpath) invalid path"         case .wrongfiletypeerror(let expectedfiletype):             return "expected type of \(expectedfiletype)"         }     } } 

_

func myfilefunction(path: string) throws {     guard let url = nsurl(string: path) else {         throw validationerror.invalidpatherror(path)     }     guard let data = nsdictionary(contentsofurl: url) else {         throw validationerror.wrongfiletypeerror(expectedfiletype: ".plist")     }     print(data) }   {     try myfilefunction("hi.jpg") } catch validationerror.invalidpatherror(let path) {     print("darn, had bad path \(path)") } catch validationerror.wrongfiletypeerror(let expectedtype) {     print("darn, expected type \(expectedtype)") }  catch (let error myapperror) {     print("darn, old error \(error.message)") } 

the compiler knows function throw validationerrors warns if try , catch myapperror. here another/better way it.

do {     try myfilefunction("hi.jpg") } catch (let error validationerror) {     switch error {     case .wrongfiletypeerror(let expectedtype):         print("darn, expected type \(expectedtype)")     case .invalidpatherror(let path):         print("darn, had bad path \(path)")     } } 

lets compare oo class/inheritance

class myapperror : customstringconvertible {     let message: string      init(message: string) {         self.message = message     }      var description: string {         return message     } }  class validationerror : myapperror {  }  class invalidpatherror : validationerror {     let path: string      init(message: string, path: string) {         self.path = path         super.init(message: message)     }      override var description: string {         return "\(path) invalid path"     } }  class wrongfiletypeerror : validationerror {     let expectedfiletype: string      init(message: string, expectedfiletype: string) {         self.expectedfiletype = expectedfiletype         super.init(message: message)     }      override var description: string {         return "expected type of \(expectedfiletype)"     } } 

_

func myfilefunction(path: string) throws {     guard let url = nsurl(string: path) else {         throw invalidpatherror(path: path)     }     guard let data = nsdictionary(contentsofurl: url) else {         throw wrongfiletypeerror(expectedfiletype: ".plist")     }     print(data) }  {     try myfilefunction("hi.jpg") } catch (let error invalidpatherror) {     print("darn, had bad path \(error.path)") } catch (let error wrongfiletypeerror) {     print("darn, expected type \(error.expectedfiletype)") } catch (let error myapperror) {     print("some other error") } 

as can see, works creating error classes adds lot of baggage. don't automatic namespacing validationerror.wrongfiletypeerror or let error validationerror. reading class knows invalidpatherror , wrongfiletypeerror caught. contrast enum version know validationerror instances being caught , compiler tells this.


Comments

Popular posts from this blog

resizing Telegram inline keyboard -

command line - How can a Python program background itself? -

php - "cURL error 28: Resolving timed out" on Wordpress on Azure App Service on Linux -