3 ms·
Conceptually, Racket's parameterize is basically just dynamic vars (though practically, it's more complex than that, because continuations etc.). If you have a
by wtetzner 8y ago
Conceptually, Racket's parameterize is basically just dynamic vars (though practically, it's more complex than that, because continuations etc.).
If you have a language that supports thread-locals and lambdas, you can get pretty far with something like:
public static S parameterize<T,S>(ThreadLocal<T> param, T value, Callable<S> body) {
T old = param.get();
param.set(value);
try {
S result = body.call();
} finally {
param.set(old);
}
return result;
}
You can then do something like:
public static final ThreadLocal<Logger> LOG = ThreadLocal.withInitial(() -> getRootLogger());
And when you need a different logger, you can do:
String result = parameterize(LOG, myFancyLogger, () -> {
return methodThatLogsThings();
});
- default-kramer 8y agoYep, this is pretty much it, except I want the type system to let me know if "methodThatLogsThings" makes it all the way to the top of the call stack without satisfying the LOG parameter. C# doesn't do that, but I think a theoretical version of C# could - just stick the implicit dependencies into an attribute on each method. For example, the compiler inserts an attribute like: [ImplicitDependency(LOG)] void methodThatLogsThings() Which would cascade up the call hierarchy until it gets satisfied.