Answer to: Are there any functional approaches, to have variables that feel global (no need to pass them around explicitly), yet are local to an instance?
Score: 4
You are correct in that lots of languages, even OOP languages use tricks like this. eg HttpContext.Current in net framework.
You need to access a context for the current operation, but rarely, so you don't want to force all the function calls or object constructors to accept a context parameter just in case its needed.
Here is a tricky way to do it in javascript I worked out, similar to your module closure approach.
class contextState
{
static run = (state, func) => {
var mystate = state;
var f = eval(String(func)) //dynamically adds the function to the closure
return setTimeout(f, mystate); //call with timeout to demonstrate state is not lost
}
}
callback = () => {
var x = mystate //still have to work out how to make this a static
console.log(x)
}
contextState.run(2000, callback)
contextState.run(1000, callback)
We can expand on this trick to use the stack trace as state, which we can read back later and use to retrieve the "global state" for the function chain.
class contextState
{
static id = 0;
static states = new Map();
static run = (state, func) => {
const id = contextState.id++;
const wrapString = `const wrap_${id}_wrap = () => {
func();
}; wrap_${id}_wrap()`
contextState.states.set(`${id}`, state);
const wrap = () => eval(wrapString) //dynamically names the function so that the id appears in the stacktrace
return setTimeout(wrap, state); //call with timeout to demonstrate state is not lost
}
static getState = () =>
{
var err = new Error();
var id = contextState.extractId(err.stack);
return contextState.states.get(id);
}
static extractId = (stack) =>
{
const regex = /wrap_(.*?)_wrap/g;
let matches = [];
let match;
while ((match = regex.exec(stack)) !== null) {
matches.push(match[1]);
}
return matches[0];
}
}
callback = () => {
var x = contextState.getState();
console.log(x)
}
callback0 = () => {
callback()
}
contextState.run(2000, callback0)
contextState.run(1000, callback0)
This mirrors the syntax of AsyncLocalState and allows user defined functions to pick up the state from the static reference.
However, If i'm weighing in on the OOP vs Functional discussion, we have to address the fact that the problem statement, wanting to include state with a function; is exactly what OOP classes do and what functional avoids.
By using this style of approach you straddle the two concepts and maybe have the worst of both.
View Question ↗
Question
Parent Entity
Score: 2 • Views: 538
Site: softwareengineering
SaaS Metrics