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: 1
Another idea, heavily inspired by the one Ewan proposed, but simpler.
I could have a mutable global variable, and update it with the current instance every time you enter it.
let myLibState; // global
// myLibrary/index.ts
import f from './f';
export class MyLibrary {
constructor(name) {
myLibState = this; // updating the global !
this.instanceName = name;
}
whatever() {
myLibState = this; // updating the global !
f();
}
}
// myLibrary/f.ts
export function f() {
return myLibState.instanceName;
}
The tricky part, just like in Ewan's answer, is to always update the global every time you enter the library instance.
Entering the library instance could mean:
The user calls a function of a library's instance. Like lib1.whatever() in the example code.
An function gets called asynchronously. For instance:
// this wouldn't work:
// functions called asynchronously might have the wrong `myLibState`
// setTimeout(f, 1000);
// here we are within the right instance
// let's back up the `myLibState`
const savedInstancemyLibState = myLibState;
setTimeout(()=>{
// to then restore it in the closure:
myLibState = savedInstancemyLibState;
return f();
}, 1000);
The user calls someClosure() that was created and returned within the library instance. For instance:
function createClosure() {
// similarly to the above, we can't just return this closure
// it might get called on a wrong `myLibState`
// return ()=>console.log(f());
// `createClosure` is called within the right instance
// let's back up the `myLibState`
const savedInstancemyLibState = myLibState;
return ()=>{
// to then restore it in the closure:
myLibState = savedInstancemyLibState;
console.log(f());
};
}
}
And if you want to allow one library instance to use another, you'd need to restore the previous global variable every time you exit an instance.
Of course some utility functions could make the process much less annoying:
function instanceRun(callback) {
const savedInstanceMyLibState = myLibState;
return ()=>{
const currentInstanceMyLibState = myLibState;
myLibState = savedInstanceMyLibState;
const out = callback();
myLibState = currentInstanceMyLibState;
return out;
};
}
// wrapping `f` for an async call
setTimeout(instanceRun(f), 1000);
// wrapping the `()=>console.log(f())` closure
function createClosure() {
return instanceRun(()=>console.log(f()));
}
However the issues remain: forgetting to wrap anything anywhere might result bugs. Subtle and very hard to find bugs.
View Question ↗
Question
Parent Entity
Score: 2 • Views: 538
Site: softwareengineering
SaaS Metrics