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: 2
As the experts in this community pointed out in the comment, the solution is obvious: use OOP, enclose the state in objects and live a happy life:
// myLibrary/index.ts
import {F} from './f';
export class MyLibrary {
constructor(name) {
// the state is `this`!
this.instanceName = name;
}
whatever() {
const f = new F(this);
f.f(); // no need to pass `f` any arguments!!!
}
}
// myLibrary/f.ts
export class F {
constructor(state) {
this.state = state;
}
f() { // look mom: no arguments!!!
return this.state.instanceName;
}
}
Makes me wonder why Node.js would bother with AsyncLocalStorage. Or why languages have thread-local storage. Or why Haskell has implicit arguments. Or why Agda's modules can be parameterized... Didn't they know they can just hide the state in objects?
In reality, this is not a real solution. state.f() and f(state) are the same thing. They are isomorphic:
// isomorphism
function methodToFn(method) {
return (state, ...args) => method.call(state, ...args);
}
function fnToMethod(fn) {
return function (...args) {
return fn.call(null, this, ...args);
};
}
// testing the isomorphism
const fn1 = (state, y) => state.x + y;
const method1 = function (y) {
return this.x + y;
};
const fn2 = methodToFn(method1);
const method2 = fnToMethod(fn1);
const fn3 = methodToFn(fnToMethod(fn1));
const method3 = fnToMethod(methodToFn(method1));
function newObject(method, state) {
return Object.assign({ method }, state);
}
const state = { x: 2 };
const y = 3;
// all these things should have the same result
console.log(fn1(state, y));
console.log(fn2(state, y));
console.log(fn3(state, y));
console.log(newObject(method1, state).method(y));
console.log(newObject(method2, state).method(y));
console.log(newObject(method3, state).method(y));
In either case you can't just use the function/method on its own, but you need to carry around its state together with it. For instance you can't do array.map(f)/array.map(state.f) but you have to do array.map(()=>f(state))/array.map(()=>state.f()).
All the solutions I mentioned (Node.js' AsyncLocalStorage, thread-local storage, Haskell's implicit parameters, Agda's parametrized modules) are meant to offer the ease of use of global variables while fixing their problem. And that's exactly what I'm looking for.
What I'm asking for is "instance-local globals". The state should be accessible via some globals which are local to the instance. No explicit passing of state, neither via argument, nor via this.
View Question ↗
Question
Parent Entity
Score: 2 • Views: 538
Site: softwareengineering
SaaS Metrics