Hacker News new | ask | show | jobs
by philosopher1234 1243 days ago
What would you do after launching a goroutine? Im very fond of contexts being explicit because it makes this situation obvious, unlike thread local variables where you have to pause and think about it.
1 comments

> What would you do after launching a goroutine?

Not sure what you mean? The context would be inherited from its parent.

I’m making two points: 1. Context should make its way down to IO, and 2. they should be implicit by default. All for the same reasons Go has automatic memory management - reducing complexity and surface area of bugs for the 99%.

Function coloring may seem innocent in a self-contained example, but become problematic at an ecosystem-level: if one player is not cooperating, the bets are off for everyone else. All dual context impls I’ve ever seen have the context free version simply invoke the other with the background context, indicating a lack of meaningful semantic distinction requiring an API level differentiation. In simpler terms, the act of choosing between either context or no context version is purely a mechanical “do I currently have a context” yes/no determination. This is prime criteria for warranting implicitness, imo.

> Not sure what you mean? The context would be inherited from its parent.

I hate dynamic scoping for the very same reason I would hate having context be inherited from the parent caller.

Not only would it would result in a function having different behaviours depending on what the call stack looked like at runtime (which is bad enough), but it would be invisible to the reader of the code.

What I like about Go is that it is very easy to visually inspect the code in code reviews.

Imagine looking at a diff in a PR that changes function `foo()` to add a call to function `bar()`, with `bar` using a context and `foo` not using a context.

Do you really want to have to read all possible call-sites to ensure that the context is what is expected when `foo()` calls `bar()`? It's easier to reason about when the `context.Context` is created at the point of calling `bar()`.

For context (hah), I’m talking purely in terms of cancelation and not context.Value() which is a whole other story, and imo should never have been created.

> I would hate having context be inherited from the parent caller.

By default. All I’m arguing is that canceling is in 99% what should be done. You could override that when it makes sense. If your parent wants you to terminate, then in what instances would you keep going? There are some use cases of graceful teardown, but I haven’t seen a single 3p developer give a shit about that, and I’d rather have them respect my desire to yield control back to me, than to go on forever because they forgot to carefully litter their codebase with SetDeadline in their IO calls.

> Do you really want to have to read all possible call-sites to ensure that the context is what is expected when `foo()` calls `bar()`?

Why would I? Unless foo or bar is a unicorn that requires the caller to prepare a custom context, it would work the same as mindlessly passing the context from parent to child, which people do today.

Take the converse example: if today I add a call to bar (no context param), I need to make sure it doesn’t block forever, and if it does, it makes my entire call tree non-cancelable, even if I have been diligent about it in every other place. It only takes one non-cooperative player to destroy that property, and the default is to not be cooperative.