0

If I call hello.f, the compiler forces me to handle all the thrown exceptions. I can swallow them using try? or add a catch all by not specifying the type of exception to catch and then re-throw. But, if I do the latter, I need to mark the calling function as throws and the process continues all the way up the stack.

Is it possible to ignore f's exceptions such that they ultimately become un-handled exceptions that can be handled globally?

enum e : Error {
    case hello
    case world
}

class hello {
    func f() throws  {
        throw e.hello
    }
}
Ian Warburton
  • 15,170
  • 23
  • 107
  • 189
  • `rethrows` doesn't appear to be in the language guide. – Ian Warburton Nov 02 '16 at 16:30
  • that is beyond my scope, I did not wrote the language guide. :) – holex Nov 02 '16 at 16:31
  • If you don't want to propagate the exception, don't rethrow it. Use `catch` and do nothing. Problem solved. – rmaddy Nov 02 '16 at 16:33
  • @rmaddy I do want to propagate the exception. I want to handle them globally. – Ian Warburton Nov 02 '16 at 16:35
  • @holex `rethrows` is applied to a function which takes a throwing function argument. I don't think that's applicable to my code. – Ian Warburton Nov 02 '16 at 16:35
  • 1
    Your title says "Avoid handling all exceptions". Please clarify what you mean. What do you mean by "handled globally"? – rmaddy Nov 02 '16 at 16:36
  • 2
    I think that you can't. It's by design. Swift is more strict on error handling. – Duyen-Hoa Nov 02 '16 at 16:37
  • 1
    @IanWarburton, yes, I revised the code I have quickly written in the comment, that was not the proper syntax, btw, but you can go for `func g() throws { try f() }` this, which is correct by now, you just forward the error in this case without handling it locally. – holex Nov 02 '16 at 16:37
  • @holex You can't do that. The compiler says, "Errors thrown from here are not handled". – Ian Warburton Nov 02 '16 at 16:40
  • @IanWarburton, nope, compiler says nothing like that, that is a live code I just copied form my test app, based on your foundation. – holex Nov 02 '16 at 16:41
  • What you want can be done using `rethrows` on each method up the chain. Then you can handle the actual exception at whichever level in the chain you want. – rmaddy Nov 02 '16 at 16:43
  • @holex aha... yes, it stops complaining when adding throws to the method. – Ian Warburton Nov 02 '16 at 16:44
  • @holex Seems to work. Please write it as an answer. The existing answer is incorrect. – Ian Warburton Nov 02 '16 at 16:52
  • @rmaddy `rethrows` is only applicable to functions that take a throwing function as an argument – marking each method up the chain as `throws` should work fine though. – Hamish Nov 02 '16 at 16:57
  • @Hamish I realize that now. Using `throws` is what I should have stated. Thanks. – rmaddy Nov 02 '16 at 16:58

3 Answers3

1

Is it possible to ignore f's exceptions such that they ultimately become un-handled exceptions that can be handled globally?

In a word, no. The entire point of the design of Swift's error handling is that you must explicitly acknowledge the possibility of error at every stage.

It sounds to me like you're thinking of how Objective-C deals with NSException, but Swift isn't like that (and Error is not like NSException).

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Coming from C#... I think Anders Hejlsberg makes a good argument against this here... http://www.artima.com/intv/handcuffs.html. – Ian Warburton Nov 02 '16 at 16:43
  • 1
    Why can't `rethrows` be used? Then you simply pass the responsibility up to the previous caller in the chain. Isn't that what the OP wants? – rmaddy Nov 02 '16 at 16:43
  • 1
    Actually, `throws` is what I should have stated, not `rethrows`. – rmaddy Nov 02 '16 at 16:58
  • @rmaddy Absolutely, but that is not "ignoring". It is acknowledging, as I said. Of course it's possible that I didn't understand what Ian was after, but I thought he wanted to percolate up the chain _without_ saying `throw` / `try` at every stage, and I'm saying, rightly, that you can't do that. – matt Nov 02 '16 at 17:01
  • Agreed that "ignoring" is not the right word (which I never used). "defer" would have been a better choice of words. – rmaddy Nov 02 '16 at 17:04
  • 1
    @rmaddy Sure. But I thought Ian really did mean "ignore". Because that is how e.g. the Responder Chain work, and how NSException handling works in Objective-C: the runtime just keeps walking up the call chain _looking_ for _someone_ to handle this thing. (But my point is, Swift error handling is not like that: _you must_ handle it somehow at every step of the walk up the call chain. – matt Nov 02 '16 at 17:08
1

based on your expectations, I have created this example:

enum PetError : Error {
    case pet
}

class Pet {
    func pet() throws  {
        throw PetError.pet
    }
}

class Cat {
    func cat() throws  {
        let pet = Pet()
        try pet.pet()
    }
}
class Tiger {
    func tiger() throws  {
        let cat = Cat()
        try cat.cat()
    }
}

then you can handle the PetError exceptions (=errors) on the highest level you need, while inside the chain the errors are just forwarded to the upper level.

let tiger = Tiger()
do {
    try tiger.tiger()
} catch PetError.pet {
    print("PetError.pet")
}

NOTE: of course you may want to handle all exceptions (=errors) at the end of the day, but that is not part of this little example.

holex
  • 23,961
  • 7
  • 62
  • 76
0

This does what I'm after. The output is "hello\n". Thanks to holex in the comments of the question.

enum e : Error {
    case hello
    case world
}

class hello {
    func f() throws  {
        throw e.world
    }
}

class goodbye {
    func g() throws  {
        let h = hello()
        try h.f()
    }
}
class world {
    func w() throws  {
        let g = goodbye()
        try g.g()
    }
}

let w = world()
do {
try w.w()
}
catch e.world {
    print("hello")
}
Ian Warburton
  • 15,170
  • 23
  • 107
  • 189
  • @holex I wanted to share more of my naming convention with the world. If you answer, I will give you the points. – Ian Warburton Nov 02 '16 at 16:59
  • @IanWarburton Speaking of naming conventions, type names should be `UpperCamelCase`, e.g `Hello`, `Goodbye`, `World` & `E`. – Hamish Nov 02 '16 at 17:00
  • 1
    Still, I do think you are just proving that what I said is right. You _must_ explicitly show the compiler at every stage of the chain that you know an error can pass this way. – matt Nov 02 '16 at 17:03
  • @IanWarburton, okay, I have posted an answer based on your code; I don't actually wanted extra credit, but I definitely against your naming conventions in Swift. – holex Nov 02 '16 at 17:09
  • @holex Arguably its not a convention. – Ian Warburton Nov 02 '16 at 17:17
  • @matt That's a good point. holex's answer is really only a partial solution. – Ian Warburton Nov 02 '16 at 17:19
  • ok, so I think @matt gives the correct answer after all. And as Anders Hejlsberg points out in the link I posted, if one is using a multitude of frameworks, one is often going to be guaranteed to be writing a fair amount of boiler plate for exceptions even if one is not interested in many of them. – Ian Warburton Nov 02 '16 at 17:22