4 ms·
Context should go away for Go 2
- Tarean 9y agoThe 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.
- captainmuon 9y agoI 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.
- Mouse47 9y agoThis might be a little out of scope, but C#/.NET has a few similar constructs. If you do: using(TransactionScope scope = new TransactionScope()){ //do stuff } Any connection created while that block is active will 'enlist' in the transaction associated with that scope. This works (I think...can't find it now) by using something called 'CallContext', which is more or less a static key-value store that's persisted up and down the call stack (including through async continuations, not sure how that works). If the 'CallContext' is static, doesn't that mean it's global and shared between threads? Well...in C# that's not necessarily true since the thread is accessible via a static property and it's possible to store data against the thread (which is exactly what 'CallContext' does, plus some magic that moves the data during async continuations in case the execution thread changes)
- Someone 9y agoScala has implicit parameters. For examples, see http://daily-scala.blogspot.nl/2010/04/implicit-parameters.html http://daily-scala.blogspot.nl/2010/04/implicit-parameters.h... (simple examples) or https://stackoverflow.com/a/9538177 https://stackoverflow.com/a/9538177 (more useful ones)
- ruste 9y agoIIRC 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 9y agoIn 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 9y agoI 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 9y agoIn 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 9y agoAaahhh! 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 9y agoCommon Lisp has dynamic scope via dynamic variables. > but it should be possible to fake them in C++ quite well. Been there done that; had a dynamic_var<T> template some seventeen year ago. It provided thread-specific rebinding and all.
- marktangotango 9y agoTCL has dynamic scope for those who don't know.
- breakingcups 9y agoI'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 9y agoQuestion, 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.
- knodi 9y agoyes, like an expended channel reference. This way you can open up this reference to handle channel management/cancellations.
- SamReidHughes 9y agoIn 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.
- Someone 9y agoThis 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."
- deleted 2y ago[deleted]