
Context should go away for Go 2 - mnmlsm
https://faiface.github.io/post/context-should-go-away-go2/
======
captainmuon
I can't speak about Go specifically, but something I'd love to see in a
language is a general "context" mechanism for passing data from a very high
scope to a very low scope, without changing the functions inbetween, and
without resorting to global variables.

A (not very good) example in pseudocode would be:

    
    
        complicated_operation(param) with context (log_out=myfile);
        // complicated_operation calls a function,
        // that calls another function...
    
        void log(string str) context (File log_out=stdout) {...};
    

This would be a bit like TLS, but has the advantage that the context reverts
after the original call.

Usually, when I have this problem, I just stuff all the functions into a
class, and make the "context" private fields. But then you end up with classes
that really "don't want to" be classes, the lifetime of the context state is
longer than necessary and unclear, and it feels like a hack. Also, in many
languages going from free functions (and plain data and closures) to classes
takes a bit of rewriting due to different syntax.

The only language I'm aware of that has these "dynamic scopes" is (apparently)
Emacs Lisp, but it should be possible to fake them in C++ quite well.

It would also make the situation in the article a lot cleaner, IMO.

~~~
ruste
IIRC scheme and probably common lisp have something like this:

(call-with-dynamic-bind ((var1 val1)(var2 val2)...) stuff...)

It lets you introduce dynamically scoped variables that work pretty much the
way you described.

~~~
kazinator
In Common Lisp this is just _let_ , where the variables are dynamic variables.

(There is a dynamic binding operator called _progv_ , but the situation for
that is when the variable names are computed.)

~~~
ruste
I don't think so. _let_ is lexically scoped. What I was remembering was a
syntax called parameterize in chicken scheme that would bind a set of values
to a set of dynamic variables. You can see an example of it here:
[https://github.com/caolan/snowy/blob/master/server.scm#L85](https://github.com/caolan/snowy/blob/master/server.scm#L85)
I don't think common lisp has an equivalent (and I'm pretty sure it's not part
of rnrs in scheme), but it should be really easy to hack one together.

~~~
kazinator
In Common Lisp _let_ is either lexically or dynamically scoped, depending on
whether the symbol is marked "special" which is the situation if the symbol
was previously used as the name in a _defvar_ or _defparameter_ form to define
a dynamic variable.

So dynamically scoped contexts are achieved just by binding these special
variables. By convention, they are usually given names beginning and ending
with an asterisk ("earmuffs") to put them into an effectively separate
namespace.

That _parametrize_ is reminiscent of _fluid-let_ ; another Scheme hack to
simulate dynamic scope.

~~~
ruste
Aaahhh! Yeah, that makes total sense. I was thinking about newly introduced
symbols using let. I recently jumped from scheme to common lisp so I'm used to
lets just shadowing other variables.

Most of the major scheme implementations I've used have had real dynamic
scoping of some sort. I don't think it's very well supported in the standard,
but they all seem to have it as a proper language feature.

~~~
kazinator
The convenient thing about special variables just using _let_ is that you can
use them in any binding construct:

    
    
        (with-output-to-string (*standard-output*)
          ... code ... )
    

Here, _code_ 's output to the default standard output stream is captured in a
string.

------
Someone
This keeps repeating _" Go is a general purpose language"_, but is it?

[https://golang.org/doc/faq#What_is_the_purpose_of_the_projec...](https://golang.org/doc/faq#What_is_the_purpose_of_the_projec...):
_" By its design, Go proposes an approach for the construction of system
software on multicore machines."_

That page points to
[https://talks.golang.org/2012/splash.article](https://talks.golang.org/2012/splash.article)
for _" A much more expansive answer to this question"_. That article states:

 _" Go is a programming language designed by Google to help solve Google's
problems [...] More than most general-purpose programming languages, Go was
designed to address a set of software engineering issues that we had been
exposed to in the construction of large server software."_

------
breakingcups
I'm glad to read this, I've seen context prop up in more and more code for a
while now and it feels like a bit of a wart on what was a good, simple
programming language.

There's a few more warts that have been added since Go 1.0, presumably to
preserve backwards compatibility. Magic comments, the forking of the syscalls
package, the vendoring experiment, the alias functionality, etc.

------
camus2
Question, how do other concurrent languages like Java or C# handle the concept
of 'thread context', and cancellation?

To me it sounds like having to pass a context everywhere is something that
should be handled on the language level, just as concurrency.

~~~
SamReidHughes
In RethinkDB which is C++ with a home rolled m:n threads library, it passes in
an "interruptor" which is like a one shot chan struct{} you can wait upon or
select over with other chans. The main difference is that the functions which
take an interruptor and throw an interrupted_exc_t exception. You could add
language support for doing this sort of stuff automatically, or very
conveniently, though it would need a bit of care when lambdas or closures get
involved.

------
Tarean
The article didn't really give an example of using contexts but from what I
can tell they are a way to add additional semantics to a function? The article
mentioned cancellation and implicit parameters at least.

My first reaction was that monads would solve the problem. Since this is go
hardcoding cancellation intonthe language probably is the best available
solution, though.

