3 ms·
Contexts are generally regarded as a workaround for the fact that Go doesn't offer goroutine-local storage -- a design feature that's often criticized.
by networkimprov 6y ago
Contexts are generally regarded as a workaround for the fact that Go doesn't offer goroutine-local storage -- a design feature that's often criticized.
- ohnoesjmr 6y agoGoroutine local storage is the stack? If you don't want to push values down as arguments and want some global state to access it, your code is probably horrible already. Pushing down a context as a value container instead of actual values is horrible too.
- jlokier 6y agoPushing down 100 arguments to every function that might call something else in the call chain is horrible too, so what are you going to do? A key-value container? Sounds like context, or goroutine-local storage with superfluous boilerplate. A "request" object containing all the values? Sounds like goroutine-local storage by another name, just more verbose. Restrict every function in the program to pass exactly the values used by any of its possible callee descendants? Sounds brittle, you'll never get anything finished.
- morelisp 6y ago> Sounds brittle, you'll never get anything finished. This is really where we are? "Lexical scoping makes programming impossible"? I have written over a dozen Go services totaling at least 50k lines of code. They all use context extensively, including at least 3 custom context types. I have not once put anything in a Value context. Things I want to pass, either: - Just pass them. Yes, some functions near the top have "too many" arguments and it sucks, but it sucks less than context k/v lookups. - Pass a configuration object. This means passing at most an argument per layer, rather than an argument per field. Type-safe, faster than a context, overall usually less boilerplate than recasting a context value. - Call bound methods. This is the "global context" you actually want in most code, containing "my net.Listener", "my sql.DB", etc. Type-safe, faster than a context, no boilerplate.
- jlokier 6y ago> This is really where we are? "Lexical scoping makes programming impossible"? No. "Pass exactly the values" is a subset of lexical scoping, which is much more brittle than lexical scoping in general. > - Pass a configuration object. This means passing at most an argument per layer, rather than an argument per field. Type-safe, faster than a context, overall usually less boilerplate than recasting a context value. So, a God-object then, what I called "request object". That's regarded by some as an anti-pattern, even though it's type safe. > overall usually less boilerplate than recasting a context value. When comparing with context, I agree. But when comparing with goroutine local storage, which the comment was about, a configuration object passed everywhere is more boilerplate not less. > bound methods. I'm not clear on what you have in mind by bound methods, unless the values are lexicals who values must remain the same across all concurrent goroutines. If that's so, "my sql.DB" probably uses thread-local storage when it needs a usable DB handle anyway, and both that and "my net.Listener" are effectively global variables, potentially breaking modular re-use within a single process.
- hehebbssjj 6y agoInstead you should push down a single argument which is an untyped key value map which may or may not contain the variables you want?