A bit of hackiness that I ended up using was pass by reference in javascript. Objects in javascript are all passed by reference so when a function gets an object, it will modify the object in place. This means you can move a primitive like a counter into an object and then use that object in a function somewhere else to continue a loop!
I ended up using this logic in my markdown parser. I wrote a function that returns a string and called that function in a few different places. It looped through characters much like my main loop that handled files. This meant that I need a single global counter variable but I don't like using globals especially since I was also using recursion.
Passing a counter variable to a function in javascript results in copying the variable so it won't be changed in the calling function. But if we embed that counter inside an object, voila! We have a pass by reference and we can make modifications to the counter in place!
function incrementCounter(i) {
for (let k=0;k<5; k++) {
i++;
}
}
let i = 0;
console.log(i);
incrementCounter(i);
console.log(i);
This will output 2 0s. This is because i is set to 0 and then the increment only happens on a copy that never gets returned and so i will be 0 even after the incrementCounter function.
function incrementCounter(i) {
for (let k=0;k<5; k++) {
i.c++;
}
}
let i = { c: 0 };
console.log(i.c);
incrementCounter(i);
console.log(i.c);
This will print 0 and 5. I don't like this code because it is quite magical and you wouldn't expect this behavior and there's nothing really in the code that signifies what's about to happen. I would love to be able to add sigil like & so that its obvious when we are doing variable manipulation on a shared object but I did end up using this logic instead of returning multiple values in my function.
I do think doing pass by reference was a good thing here because it simplifies a few things but it does make everything more brittle. I think the real solution might've been to use a class based structure to track variables instead of going the route of writing functions to do everything. I can definitely see how classes would get rid of a lot of the junk code that I have to pass many things around. Maybe at some point I'll take a stab at rewriting my markdown parser.