Live data from Hacker News

Conc: Better Structured Concurrency for Go

github.com

151–160 of 162 posts

Re: Conc: Better Structured Concurrency for Go

#151

Earlier quoted context omitted.

If there is no way for callers to reliably distinguish recoverable panics from unrecoverable panics, then this distinction doesn't really exist, does it? Panics are panics.

I'm not sure what point you are trying to make anymore. Of course you cannot distinguish between unrecoverable and recoverable panics, because by definition an unrecoverable panic is not recoverable. There is no caller to distinguish between it - it is killed.

Oh. You're using the word panic to describe a superset of actual panics and other even more serious errors. Those things you call unrecoverable panics are not actually panics.

The point I'm trying to make is that panics are not errors by another name, and they are not safe to recover from in general.

Re: Conc: Better Structured Concurrency for Go

#152
post #143

Earlier quoted context omitted.

That's a style decision, not a correctness issue. You are claiming it is a correctness issue.

It is absolutely a correctness issue. Panics do not provide safety guarantees that generalize enough that it is safe to arbitrary recover from them. The statement in the previous sentence is not a subjective opinion, it's a statement of fact. I'm not sure how else to convey this information.

Panics do not violate any runtime guarantees, and defers run in the presence of panics.

All safety guarantees possible if there were no panics are possible with.

Re: Conc: Better Structured Concurrency for Go

#154

Earlier quoted context omitted.

I'd not be so sure. Accepting that everything that can fail will fail shaped me as a young developer, and "Exceptional C++" had a huge influence on me. Now my approach for new code I review is this: * Make sure you support properly unrolling the stack * Keep a clean failure boundary, probably somewhere on top of your loop * Fastidiously check your preconditions * Fail brutally if they're not met * Improve from there

Right, all of these are good points, but the problem is that the "failure boundary" of a panic is the entire process. You can't constrain it, or assume that it's scoped to a single goroutine. Errors do not have this property.

> the "failure boundary" of a panic is the entire process.

This is trivially falsifiable by panicking yourself and immediately recovering. Neither failure domain nor failure boundary need to align with the entire process.

Re: Conc: Better Structured Concurrency for Go

#155

Earlier quoted context omitted.

Right, all of these are good points, but the problem is that the "failure boundary" of a panic is the entire process. You can't constrain it, or assume that it's scoped to a single goroutine. Errors do not have this property.

> the "failure boundary" of a panic is the entire process. This is trivially falsifiable by panicking yourself and immediately recovering. Neither failure domain nor failure boundary need to align with the entire process.

The impact of a specific panic does not extrapolate to the impact of all panics, and my claim is not falsified by such an example. Panics are defined by the language to represent unrecoverable errors.

    func (x *Thing) Method() {
        x.somethingThatPanics()
        x.somethingThatAssumesTheAboveDidntPanic()
    }
Recovering from a panic thrown by Method invalidates the state of the Thing which threw that panic. If that Thing is shared among concurrent actors, the entire program state is invalidated.

Re: Conc: Better Structured Concurrency for Go

#156

Earlier quoted context omitted.

> the "failure boundary" of a panic is the entire process. This is trivially falsifiable by panicking yourself and immediately recovering. Neither failure domain nor failure boundary need to align with the entire process.

The impact of a specific panic does not extrapolate to the impact of all panics, and my claim is not falsified by such an example. Panics are defined by the language to represent unrecoverable errors. func (x *Thing) Method() { x.somethingThatPanics() x.somethingThatAssumesTheAboveDidntPanic() } Recovering from a panic thrown by Method invalidates the state of the Thing which threw that panic. If that Thing is shared…

> If that Thing is shared among concurrent actors

You're adding preconditions to your claim.

> the entire program state is invalidated.

No, the state represented by a connected graph of variables accessible by the concurrent actors is tainted. This is hardly "the entire program state". Often it's just a few cache entries.

Also, see my first, most important, bullet point:

"* Make sure you support properly unrolling the stack."

Which means a request to Thing errored out, but it never enters an invalid state. If you fail at that, all bets are off. But then you're dealing with a mediocre codebase anyway.

And finally, let me rewrite your example to something, that I see much more often in real life code, which problematic _even without concurrent actors_ because somethingThatAssumesTheAboveDidntReturnAnError might do horrible things all by themself:

func (x *Thing) Method() {

x.somethingThatReturnsAnError()

x.somethingThatAssumesTheAboveDidntReturnAnError()

}

Re: Conc: Better Structured Concurrency for Go

#157

Earlier quoted context omitted.

The impact of a specific panic does not extrapolate to the impact of all panics, and my claim is not falsified by such an example. Panics are defined by the language to represent unrecoverable errors. func (x *Thing) Method() { x.somethingThatPanics() x.somethingThatAssumesTheAboveDidntPanic() } Recovering from a panic thrown by Method invalidates the state of the Thing which threw that panic. If that Thing is shared…

> If that Thing is shared among concurrent actors You're adding preconditions to your claim. > the entire program state is invalidated. No, the state represented by a connected graph of variables accessible by the concurrent actors is tainted. This is hardly "the entire program state". Often it's just a few cache entries. Also, see my first, most important, bullet point: "* Make sure you support properly unrolling th…

I'm not sure how to respond to this. You seem to believe that panics express problems which are constrained to the call stack which instantiated the panic. This isn't true. But I'm not sure how to express this to you in a way that will convince you. So I guess we're at a stalemate.

Re: Conc: Better Structured Concurrency for Go

#158

Earlier quoted context omitted.

> If that Thing is shared among concurrent actors You're adding preconditions to your claim. > the entire program state is invalidated. No, the state represented by a connected graph of variables accessible by the concurrent actors is tainted. This is hardly "the entire program state". Often it's just a few cache entries. Also, see my first, most important, bullet point: "* Make sure you support properly unrolling th…

I'm not sure how to respond to this. You seem to believe that panics express problems which are constrained to the call stack which instantiated the panic. This isn't true. But I'm not sure how to express this to you in a way that will convince you. So I guess we're at a stalemate.

> You seem to believe that panics express problems which are constrained to the call stack which instantiated the panic.

Not inherently, but it's your job as a developer to make sure this is the case, that's what:

"* Make sure you support properly unrolling the stack."

means.

In case you're dealing with unknown code it's your job to find out what the connected graph of potentially tainted objects is and discard them. That's what "keep a clean failure boundary" means.

If you can't, because you don't want to (short lived process, prototypes) or are unable to (hairy ball of code), tearing down the process is indeed the only option and a sane fallback choice made by the language designers. But it's not necessarily a hallmark of robust software.

I hope I had a final shot to clear up what I meant, thanks for the discussion anyway.

Re: Conc: Better Structured Concurrency for Go

#159

Earlier quoted context omitted.

I'm not sure how to respond to this. You seem to believe that panics express problems which are constrained to the call stack which instantiated the panic. This isn't true. But I'm not sure how to express this to you in a way that will convince you. So I guess we're at a stalemate.

> You seem to believe that panics express problems which are constrained to the call stack which instantiated the panic. Not inherently, but it's your job as a developer to make sure this is the case, that's what: "* Make sure you support properly unrolling the stack." means. In case you're dealing with unknown code it's your job to find out what the connected graph of potentially tainted objects is and discard them.…

In Go when some code writes `panic` it is expressing an error condition which should not be intercepted by callers and is expected to terminate the process. A panic is not an error, and panics should not be recovered as if they were errors.

Re: Conc: Better Structured Concurrency for Go

#160
post #152

Earlier quoted context omitted.

It is absolutely a correctness issue. Panics do not provide safety guarantees that generalize enough that it is safe to arbitrary recover from them. The statement in the previous sentence is not a subjective opinion, it's a statement of fact. I'm not sure how else to convey this information.

Panics do not violate any runtime guarantees, and defers run in the presence of panics. All safety guarantees possible if there were no panics are possible with.

When some bit of code invokes `panic` it is saying that there is an error which is unrecoverable, and the default expectation is that the process will terminate. There is no way to assert that panics do not violate runtime or memory model expectations. They can.
Post reply on HN