3 ms·
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 v
by captainmuon 9y ago
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.
- 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.