Global Variables and Shared State in bash (and beyond!)
another one from reddit, this time on the bash subreddit and while the conversation started based on a particular script, it transitioned to general programming concepts that apply elsewhere, in this case global variables and shared state (original thread).
a global variable is one that exists and is accessible from any part of your program, the variables you’re using (and probably the only ones you know about) are globals, notice that for instance the
$upper variable is first created at the top of the script but then
playgame() reads it and
start() updates its value, this is shared state.
ideally functions should be self-contained which means that they shouldn’t access variables that exist outside their own code nor create new ones that would “leak” to the outside after they return, in bash all variables are global by default but inside a function you can use the
local keyword to create variables that exist only there and not in the outside.
that solves the last half of our predicament, which is to not “leak” data to the outside world, the other half is solved pretty easily, instead of reading global variables use parameters when calling the function.
with this two things we can have a self-contained function, that is one that does not depend on the state of the external world to properly function, this has several advantages:
your functions become more reusable and more robust
the problem with the globals is that your function depends on the existing conditions of the environment to work properly, imagine you had a typo and instead of “upper=100” it was “uper=100” now calling
start() would break, because it expects the variable
$upper to exist and have a numeric value.
of course if you’re using parameters and don’t pass anything it’ll also break and in the same way as before, however when you debug and find that the problem is that
$upper is missing you’ll be able to trace the function call and know exactly at which point the call being made does not include the desired argument.
if you have the same situation but with a global varaible instead, not only you have to scan the whole program for the definition of the variable (since it could be ANYWHERE) but you also have to trace the program execution from the start up to the point where the missing variable is required and this because even if the varaible would be correctly defined where you expect it, there could be another point in your program (again ANYWHERE) where it’s being assigned a wrong value or deleted entirely, always using parameters helps you with this because it creates a traceable path for you to verify and locate the error.
that’s for robustness, now your parameter-based functions are also more reusable because -when called appropiately- they’ll have everything they need to operate regardless of which part of the code or even which program they’re being executed from! that’s what self-contained means here, the function can operate as long as it’s called appropiately, it does not depend on certain environmental conditions to work.
your code is more readable
when I was studying your script I got confused at some point because the
start() function and the
playgame() function communicate implicitly thru the
the thing is, when you have shared state the code of a function is not just the body of it, in order to understand it you need to understand everything that is happening on the outside and this is a really big problem, imagine this same situation but in a large-scale system with hundreds of files and thousands of lines of code.
on the other hand when you have a function that is self-contained you just need to focus on that to understant what it does, you won’t know what it’s used for or where but you’ll be able to tell what it does because everything the function needs is right there so it’s easier for you to follow and understand it and being able to break large problems into smaller pieces is key, that’s how we humans can build projects and work on systems so complex that no single person would be able to comprehend entirely on its own, “divide and conquer” it works.