> > During Semantic's interpretation passes, invalid code (unbound variables, type errors, infinite recursion) is recognized and handled based on the pass's calling context. … And given Go's lack of exceptions, such a feature would be entirely impossible.
Nonsense! It’s completely possible — you just have to be willing to abuse a few of Go’s features in order to do it.
First off, Go does have a standard calling-context (i.e. dynamic context) mechanism: context.Context[0]. All you need to do in order to track stuff in the calling context is stash an object in the … context.
Given this dynamic context mechanism, you next need a way to represent handlers. That’s easy: a handler is a function which takes an exceptional condition and either handles it or returns; handling consists of a transfer of control. Fortunately, Go has a control-transfer primitive as well: panic. So to handle a condition, a handler just panics — something higher up the call stack can use defer to catch the panic and continue execution.
That leads to the next component necessary: a way to provide resumption points, or restarts. A restart is just a function which is invoked by a handler, potentially with arguments, and which when invoked continues execution from its establishment point. This can be done with defer.
So it’s perfectly possible with tremendous abuse of Go’s panic/defer mechanism, no different from Java.
Honestly, I don’t even know if I’d call it tremendous abuse, although it is somewhat abusive. Abstracted in a library, it might even be somewhat useful.
It’s off-the-cuff — I haven’t fully considered the semantics of the different context objects being passed around.
Nonsense! It’s completely possible — you just have to be willing to abuse a few of Go’s features in order to do it.
First off, Go does have a standard calling-context (i.e. dynamic context) mechanism: context.Context[0]. All you need to do in order to track stuff in the calling context is stash an object in the … context.
Given this dynamic context mechanism, you next need a way to represent handlers. That’s easy: a handler is a function which takes an exceptional condition and either handles it or returns; handling consists of a transfer of control. Fortunately, Go has a control-transfer primitive as well: panic. So to handle a condition, a handler just panics — something higher up the call stack can use defer to catch the panic and continue execution.
That leads to the next component necessary: a way to provide resumption points, or restarts. A restart is just a function which is invoked by a handler, potentially with arguments, and which when invoked continues execution from its establishment point. This can be done with defer.
So it’s perfectly possible with tremendous abuse of Go’s panic/defer mechanism, no different from Java.
See this gist: https://gist.github.com/r13l/2911f93cbe66fb4ed50f9d9eb1eb252...
Honestly, I don’t even know if I’d call it tremendous abuse, although it is somewhat abusive. Abstracted in a library, it might even be somewhat useful.
It’s off-the-cuff — I haven’t fully considered the semantics of the different context objects being passed around.
0: https://golang.org/pkg/context/