FWIW the common name for this is "dynamic scope": https://en.wikipedia.org/wiki/Scope_(computer_science)#Dynamic_scope
The general reason this has not been accepted for Go, is that passing a Context explicitly removes ambiguities what is meant, in the presence of closures and goroutines. If you pass a closure to a different execution context (e.g. via a channel), it has two bindings for any dynamically scoped variable: One in the source stack and one in the destination stack. Neither of these seems more clearly correct than the other. Note, for example, that a callback could be called from a different goroutine altogether, yet close over the lexical scope of the function it's defined in. Goroutines also open some questions on how to efficiently implement this without races. To be fair, Context has the same issue, but by being a library type, it's used more sparingly, so the performance question is less critical. Ultimately, I don't think a lot has changed about this question over the years. On Fri, Feb 16, 2024 at 10:43 PM Sam Vilain <s...@vilain.net> wrote: > Hi all, > > Many moons ago I wrote a proposal > <https://groups.google.com/g/golang-nuts/c/o3fFHNhiNQs/m/bAyb_5dOCAAJ> to > make *execution context* a fundamental concept in Go, effectively moving ` > context.Context` to being part of the language, not just an extension. > > The main reason to do this is that then it would not be up to the source > maintainer to have to do the refactoring it takes to retrofit `ctx > context.Context` arguments passed to functions as the first position, as > has become the common boilerplate. In some places, this is impossible: for > instance, the io.Reader and related interfaces forbid a `context.Context` > argument, so a reader cannot know where it is being read from. > > Why does that matter, you might ask? The main reason is for > observability: tracing, logging, debugging, etc. Of course, context should > in general not be used to alter behavior, but for observability, it seems > like it would be fair game for the append–only map that `Context` > provides, to be available even when working with less than stellar code. > > I'm wondering how people would feel about this now? > > A summary of my original proposal would be to add a "soft" keyword (" > context") which is only meaningful when used before "var", but would not > be prohibited from being a variable name. I did some experimentation with > the go parser and found I could get code with 'context' added to is passing > the parsing tests, so I'm pretty sure this would work without slowing > things down. That's the syntax I'll use in this message, but of course > this is subject to feedback and taste. > > Some basic principles stated as text for discussion; there are code > examples in the original proposal from August 2017. > > - Semantically, creating a new scope creates a new execution context. > Hopefully that is a tautology. > - Context Variables can be declared in any execution context, using > `context > var` instead of plain `var`, and assuming the `context var` is in > scope of the observer, to all execution scopes created from that execution > context, including goroutines. > - The reverse is not true: the only way you can see changes to a > variable declared in a high level context, is if the variable has a > pointer, and the sub–level context changes it (i.e., there's no "magic > const effect" of declaring a variable with context var.) > - Functions that don't declare context variables use the same context > as their caller for retrieving context variables. > - Declaring it without assigning it in a function allows you to > read it, without changing the context. Like other variables declared > without an assignment, reading it from a context with no parent context > that has assigned it would reveal the zero value. > - You can refer to the old value in the rvalue of the declaration, > or at any point from when you declare it to when you assign it within a > function. However, having an assignment in the scope should be thought > of > creating a new context immediately with an implicit assignment at the > declaration. I think this behavior keeps the semantics as unambiguous > as > possible, and avoids having to do funny stuff when assigning the > variable > late in a function. > - Scope would work differently. While the *state* of the value > follows the execution context, the visibility of the variable would be > defined by (a) the package the variable is declared in, and (b) the Case of > the variable. > - `context var localInfo` can only be read and written in the > package it is declared in. > - While reading the rest of this, be careful not to think of the > Monty Python Spam song, as this is about Spans, which are not the same. > - `context var OpenSpan Span` declares an exported context > variable, which can be accessed as below: > - declaring `context var tracing.OpenSpan` would mean to access the > `OpenSpan` context variable exported by the `tracing` package. > This would only be a compile error if the `tracing` package has no > `context > var OpenSpan x` statement in it. > - Simply *reading *the context variable from outside the package > might not need a special syntax: `(tracing.OpenSpan)` to read it > might work just fine, to allow eg: > `tracing.OpenSpan.Log("happening", tracing.Tag("id", id))` > - Finally, `context var tracing.OpenSpan = > tracing.OpenSpan.New("canBeSlowFunc", tracing.InternalKind, ...)` > is an example of how you could work with the exported context variables > from a package. The example there is an idiomatic way for a function to > declare that it is doing something that can be expensive, and so is > worthy > of tracing representation with a new Span. `Span.New()` would be a > function that returned a new sub–span of the original Span. > > Anyway I think that's the nutshell of it. Thoughts/questions/concerns? > > Cheers, > Sam > > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/24843040-a0f2-4054-8912-acf9defb7697%40vilain.net > <https://groups.google.com/d/msgid/golang-nuts/24843040-a0f2-4054-8912-acf9defb7697%40vilain.net?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAEkBMfGNHCm8JDbWQcEaP0dWc4PhfG-wyTbuZHHVbxKF8jG_-A%40mail.gmail.com.