"It's my understanding that one can use "goroutines" to implement your own rather powerful control structures. I'm not sure one really needs exceptions if you have goroutines, channels, and multiple return values. On the other hand, there are very compelling reasons for not having exceptions, given goroutines and channels."
The "goroutines" are just threads. They're not useful for building control structures. Unless you have continuations/a reified control stack or program in a monadic style (which would essentially be CPS in this case), you cannot "fake" exceptions.
I'm not talking about "faking" exceptions. I'm talking about just not using them. Instead of "catching" exceptions down (up? In my debugger, it's down) the stack, you can just detect errors and send something down a channel. If you can conveniently send the current function's pointer, or better yet, the current context, you can do much of what you'd use exceptions for.
How do you detect errors? That's the question that the exception-handling part of exceptions is designed to solve. Having every function need a reference to a channel is really no different than error detection using return codes.
You can build one-shot continuations on top of asymmetrical co-routines, though, and multi-shot continuations if you can copy them. I don't know about "goroutines", but I've done it with the co-routines in Lua.
The "goroutines" are just threads. They're not useful for building control structures. Unless you have continuations/a reified control stack or program in a monadic style (which would essentially be CPS in this case), you cannot "fake" exceptions.