How do top-level `try` expressions work?

I understand how try, try? and try! work generally, and understand top-level await etc, but I'm struggling to figure out what happens when a line like this fails with an exception:

let file = try AVAudioFile(forWriting: invalidURL, settings: settings)

I assumed that a line like that would need to be inside a do-catch or a function that explicitly throws, as there's no way to handle the error here. I'm confused??

Thanks for taking the time.

I always assumed that try at the top level functions the same as try!. I decided to test it with this short code:

struct E: Error {}

func yeet() throws {
  throw E()
}

try yeet()

This gives the error message Swift/ErrorType.swift:200: Fatal error: Error raised at top level: main.E(), followed by a backtrace, and finally the text

When I replace the try with try!, the exact same thing happens, except that the first line of the error message is now main/main.swift:11: Fatal error: 'try!' expression unexpectedly raised an error: main.E(). I still get a backtrace and the "illegal instruction" message.

So, it would appear that at the top level, the only difference between try and try! is the wording of the error message.

2 Likes

There is a difference in the presence of defer statements and most likely deinitializers too. This program prints "Hello, world!", but doesn't if try is replaced with try!.

struct E: Error {}

func yeet() throws {
    throw E()
}

defer { print("Hello, world!") }
try yeet()
4 Likes

I see. Thank you both for your help. Much appreciated.