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.
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.
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.