6 ms·
> somebody got flamed harshly when he mentioned using a global variable. Harsh bashing on global variables is such a dumb thing. Yes, they can be dangerous. Y
by Jorengarenar 5y ago
> somebody got flamed harshly when he mentioned using a global variable.
Harsh bashing on global variables is such a dumb thing.
Yes, they can be dangerous. Yes, many had problems due to using them. Yes, we should tell beginners to avoid globals.
But there is no reason to ban them altogether. Experienced programmers should utilize them whenever it makes sense (instead of passing down a value of a local one to almost every function [sic]).
- nyanpasu64 5y agoGlobal mutable variables are generally a bad idea because they have nonlocal side effects which are difficult to mitigate, like aliased mutable pointers but worse. Extra non-aliasing arguments and multiple return values are free of these issues, and a better tradeoff in almost all cases (unless you're sure you'll never run 2 instances of a system in the same address space, and you have specialized constraints possibly including embedded/safety-critical development and emulators). When experienced programmers utilize global variables whenever it makes sense, it tends to bite future generations. Windows's GetLastError is a mess (some functions set it on error but don't clear it on success), I'm not sure about POSIX's errno, and when threads were introduced, these variables had to be changed to thread-local state.
- kayodelycaon 5y ago> When experienced programmers utilize global variables whenever it makes sense, it tends to bite future generations. Usually. There is one pattern I keep using in Rails to inject the current_user for the request into the model layer. At the beginning of a request, Thread.current[:current_user] gets set to the current_user. At the end of the request, it's cleared. For those unfamiliar, each Thread has its own Hash object and [] and []= instance methods to access it. It's a way to create global variables scoped to the current thread. To hide this implementation detail, I wrap this functionality in ApplicationRecord.current_user and ApplicationRecord.current_user= methods so no one accidentally uses :curent_user. The most common use case for this is to automatically set created_by and updated_by on a model, the same way created_at and updated_at are set. Cron jobs can do something like ApplicationRecord.current_user = User.cron_user if needed. Ideally, I would set this in a CronTask parent class so current_user is always available in the model layer. I always document these methods and explain exactly what is happening and why. Abstracting away from the implementation detail mitigates most of the problems with a global variable. Obviously, the Thread.current method does not work at all if you're using an event or actor driven architecture. Rails does a thread (or process) per request, so this works extremely well.
- lucumo 5y ago> It's a way to create global variables scoped to the current thread. That's not a global variable; that's a thread-scoped variable. (It's also not (really) mutable. It gets initialized at the start of the scope and gets removed at the end of scope.)
- ww520 5y agoFor service directory lookup, global variable is fine. For global scope queue, global variable is fine. For global scope logging service, global variable is fine.
- sagichmal 5y agoEach of these things prevents isolated testing of dependent components. For that reason alone they are nonstarters.
- ori_b 5y agoglobalvar = new NopImpl() works fine for testing. If you squint, you can even think of dependency injection frameworks like Dagger as a lot of boilerplate around a global database of instantiations.
- deleted 5y ago[deleted]
- dcow 5y agoUntil you try to run two tests at once, one which requires NopImpl and one which requires the real impl.
- sagichmal 5y agoAs dcow pointed out, it really doesn't work fine for testing, as it couples what should be isolated tests together, and prevents them from being executed concurrently.
- User23 5y agoThis is one of the reasons GNU Emacs will probably never be symmetrically multithreaded.
- xorcist 5y agoThat big backing relational database of yours contains tables of "global mutable variables". The non local side effects are part of the point.
- Chris2048 5y agoBut here's the thing: aren't most alternatives to global, some other kind of global state anyway, but possibly better managed?
- throwaway889900 5y agoSingletons come to mind as being a better alternative in languages that can do that sort of thing.
- sagichmal 5y agoSingletons are globals, aren't they?
- dcow 5y agoKinda depends. Single instance things are usually globally referenced, but as long as you're referencing an instance and not a static thing they're not hard to convert to an "injected" dependency if you need to provide a test impl to some thing being tested. The real problem is static things that can't be swapped out because you're actually calling static methods on some class rather than sharing an instance and calling instance methods.
- Chris2048 5y agoI see your point, but aren't all those things architecture dependent i.e. dependent on the implementation of the prog-lang environment?
- dcow 5y agoYes.
- sagichmal 5y agoI understand "singleton" as "only one exists" and "it exists in the global scope". That is, if I create one instance of something in my `int main()` that's not enough for it to be a singleton. That's important, because there's more than one way to enter your program. Notably, tests don't flow through your main entrypoint.
- jerhewet 5y ago> Yes, we should tell beginners to avoid globals. Welcome to Dependency Injection in .Net Core! "Those who cannot remember the past are condemned to repeat it." -- George Santayana
- userbinator 5y agoOn the contrary, I think beginners should use them because it reduces cognitive load in tiny applications. My standard rebuttal to anti-global dogmatism is "there's only one instance, and never needs to be more. If/when we do, we can consider doing something else."
- deleted 5y ago[deleted]