TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Global variables are not the problem

80 pointsby levodelellis3 months ago

30 comments

Jtsummers3 months ago
The bug in the program reveals a poor understanding of object lifecycles by whoever wrote it. The `obj` argument to `simple` is not globally unique and so it makes a poor location to store global state information (a count of how often `simple` is called, in this example).<p>Never tie global state information to ephemeral objects whose lifetime may be smaller than what you want to track. In this case, they want to know how many times `simple` is called across the <i>program&#x27;s</i> lifetime. Unless you can guarantee the `obj` argument or its `counter` member exists from before the first call to `simple` and through the last call to `simple` and is the only `obj` to ever be passed to `simple`, it is the wrong place to put the count information. And with those guarantees, you may as well remove `obj` as a parameter to both `simple` and `complex` and just treat it as a global.<p>State information needs to exist in objects or locations that last as long as that state information is relevant, no more, no less. If the information is about the overall program lifecycle, then a global can make sense. If you only need to know how many times `simple` was invoked with a particular `obj` instance, then tie it to the object passed in as the `obj` argument.
评论 #42913865 未加载
评论 #42913876 未加载
评论 #42913774 未加载
评论 #42914264 未加载
评论 #42915328 未加载
billforsternz3 months ago
From the article&gt; &quot;Static Function Variable: In C inside a function, you can declare a static variable. You could consider this as a local variable but I don&#x27;t since it&#x27;s on the heap, and can be returned and modified outside of the functions. I absolutely avoid this except as a counter whose address I never return.&quot;<p>These variables are not on the heap. They are statically allocated. Their visibility is the only thing that differentiates them from global variables and static variables defined outside of functions.<p>I think such variables can be useful, if you need a simple way of keeping some persistent state within a function. Of course it&#x27;s more state you are carrying around, so it&#x27;s hard to defend in a code review as best practice.<p>Amusingly, you can modify such variables from outside the function, simply by getting your function to provide the modifying code with a pointer to the variable, eg by returning the variable&#x27;s address. If you do that though you&#x27;re probably creating a monster. In contrast I think returning the value of the static variable (which the author casts shade on in the quote above) seems absolutely fine.<p>Edit: I should have stated that the number one problem with this technique is that it&#x27;s absolutely not thread safe for obvious reasons.
评论 #42916358 未加载
评论 #42915941 未加载
评论 #42921416 未加载
评论 #42915075 未加载
hansvm3 months ago
Global variables (in languages where they otherwise make sense and don&#x27;t have footguns at initialization and whatnot) have two main problems:<p>1. They work against local reasoning as you analyze the code<p>2. The semantic lifetime for a bundle of data is rarely actually the lifetime of the program<p>The second of those is easy to guard against. Just give the bundle of data a name associated with its desired lifetime. If you really only need one of those lifetimes then globally allocate one of them (in most languages this is as cheap as independently handling a bunch of globals, baked into the binary in a low-level language). If necessary, give it a `reset()` method.<p>The first is a more interesting problem. Even if you bundle data into some sort of `HTTPRequest` lifetime or whatever, the fact that it&#x27;s bundled still works against local reasoning as you try to use your various counters and loggers and what have you. It&#x27;s the same battle between implicit and explicit parameters we&#x27;ve argued about for decades. I don&#x27;t have any concrete advice, but anecdotally I see more bugs from biggish collections of heterogeneous data types than I do from passing everything around manually (just the subsets people actually need).
评论 #42915009 未加载
darioush3 months ago
Global variables are a programming construct, which like other programming constructs is neither bad nor good. Except, due to the takeover of workplaces by the best practices cult, instead of reasoning about tradeoffs on a case by case basis (which is the core of coding and software engineering), we ascribe a sort of morality to programming concepts.<p>For example, global variables have drawbacks, but so does re-writing every function in a call-stack (that perhaps you don&#x27;t control and get callbacks from).<p>Or if you are building a prototype, the magic of being able to access &quot;anything from anywhere&quot; (either via globals or context, which is effectively a global that&#x27;s scoped to a callstack), increases your speed by 10x (since you don&#x27;t have to change all the code to keep passing its own abstractions to itself as arguments!)<p>Functions with long signatures are tedious to call, create poor horizontal (which then spills over to vertical) code density. This impacts your ability to look at code and follow the logic at a glance, and perhaps spot major bugs in review. There&#x27;s also fewer stuff for say copilot to fill in incorrectly, increasing your ability to use AI.<p>At the end, every program has global state, and use of almost every programming construct from function calls (which may stack overflow) or the modulus operator (which can cause division by zero), or sharing memory between threads (which can cause data races) requires respecting some invariants. Instead, programmers will go to lengths to avoid globals (like singletons or other made up abstractions -- all while claiming the abstractions originate in the problem domain) to represent global state, because someone on the internet said it&#x27;s bad.
评论 #42921180 未加载
评论 #42928271 未加载
robertlagrant3 months ago
I think this article broadens the definition of global variable and then says &quot;Look, the things I added to the definition aren&#x27;t bad, so global variables aren&#x27;t always bad.&quot;<p>If you just look at what people normally mean by global variable, then I don&#x27;t think the article changes minds on that.
评论 #42918536 未加载
serbuvlad3 months ago
I find the concept of a context structure passed as the first parameter to all your functions with all your &quot;globals&quot; to be very compelling for this sort of stuff.
评论 #42913926 未加载
评论 #42913687 未加载
评论 #42918743 未加载
评论 #42913790 未加载
评论 #42913326 未加载
评论 #42913434 未加载
评论 #42915773 未加载
评论 #42919001 未加载
评论 #42913523 未加载
SpicyLemonZest3 months ago
&gt; The problem is data access. Nothing more, nothing less.<p>I agree with this, but the problem with global variables is precisely that they make bad data access patterns look easy and natural. Speaking from experience, it’s a lot easier to enforce a “no global variables” rule than explain to a new graduate why you won’t allow them to assign a variable in module X even though it’s OK in module Y.
评论 #42913860 未加载
PeterStuer3 months ago
The one where the author <i>almost</i> rediscovers the singleton pattern.
评论 #42916069 未加载
bb883 months ago
Please no.<p>Singletons if you must. At least you can wrap a mutex around access if you&#x27;re trying to make it thread safe.
评论 #42913357 未加载
评论 #42913275 未加载
评论 #42913839 未加载
评论 #42916563 未加载
Tainnor3 months ago
&gt; If you run the code you&#x27;ll see 1 2 3 4 3 printed instead of 5.<p>I&#x27;m really confused, as this behaviour appears to be completely obvious to me.
评论 #42916662 未加载
qalmakka3 months ago
<i>mutable</i> global variables are intrinsically incompatible with a multithreaded environment. Having mutable shared state is never the right solution, unless you basically can live with data races. And that&#x27;s before taking maintainability in consideration too
Puts3 months ago
I think the author forgot the most useful use case for globals, and that is variables that has to do with the context the program is running under such as command line arguments and environment variables (properly validated and if needed escaped).
评论 #42913772 未加载
js83 months ago
Any program that uses a database has a very similar problem to global variables.<p>As Gilad Bracha has pointed out, types are antimodular, and your database schema can be considered one giant type that pervades your program, just like globals can be.<p>I don&#x27;t think we have tools to compositionally solve this, across different programming languages.
评论 #42916068 未加载
评论 #42916212 未加载
pdimitar3 months ago
&gt; <i>The problem is data access. Nothing more, nothing less. There&#x27;s a term for this that has nothing to do with global variables: &quot;action at a distance.&quot;</i><p>I mean yes, using global variables is just one of the ways to cause action-at-a-distance and that is... apparently a big reveal?<p>Otherwise sure, there is no pattern that cannot be utilized 100% correctly and without introducing bugs. Theoretically. Now let&#x27;s look at the practical aspects and how often indiscriminately using such tempting patterns like global variables -- and mutexes-when-we-are-not-sure and I-will-remember-not-to-mutate-through-this-pointer -- lead to bugs down the road.<p>The answer is: fairly often.<p>IMO the article would be better titled as &quot;There is no pattern that a lazy or careless programmer cannot use to introduce a bug&quot;.
Joel_Mckay3 months ago
There are only a few use-cases where global variables make sense:<p>1. Thread container registry with mutex lock for garbage collection and inter-process communication (children know their thread ID)<p>2. volatile system register and memory DMA use in low level cpu&#x2F;mcu (the compiler and or linker could pooch the hardware memory layout)<p>3. Performance optimized pre-cached shared-memory state-machines with non-blocking magic<p>4. OS Unikernels<p>Not sure I have seen many other valid use-cases that splatter language scopes with bad&#x2F;naive designs. YMMV =3
AdieuToLogic3 months ago
This assertion made in the article invalidates the premise of same:<p><pre><code> With a little encapsulation, you can make globals error-proof ...</code></pre>
评论 #42914427 未加载
G_o_D3 months ago
Globals are essential to track state&#x2F;values of variables in intermediate step, for debug, I create unique object on globals and store intermediate variables in it, so i can inspect values when something goes wrong, being only one unique object to maintain it will not override any existing vars thus not affecting existing programs
grandempire3 months ago
I&#x27;ve recently found it helpful to think of problems at the scope of an individual process, rather than a set of functions in a library or framework. This makes it much clearer when a global variable makes sense or not, and generally where to initialize things, and place state.
debeloo3 months ago
It&#x27;s just like saying guns are not the problem.<p>Perhaps a unicorn doesn&#x27;t die as soon as you first use a global var. But it has two .45s pointed to it cranium left and right. And at any random moment Danni DeVito will start blasting.
tedk-423 months ago
Global variables are fine when you read many times, but you write to them sparingly and when they are updated but the old value is read&#x2F;used you have mechanisms to handle errors and retry
fergie3 months ago
Surely both of the examples in the article are using global variables? Nobody ever said global variables are ok if they are an object? (Or did they?)
brainzap3 months ago
There are also things like translation, environment details and logger, which I wish were always present, like a super global.
senderista3 months ago
Instance variables are to instance methods what global variables are to free functions and have exactly the same problems.
评论 #42915418 未加载
cies3 months ago
&gt; Global Variables Are Not the Problem<p>It should have been &quot;Mutability is the Problem, Globalness is not&quot;.
评论 #42922848 未加载
sennalen3 months ago
Did a global variable write this?
paulsutter3 months ago
SQL databases are global variables
评论 #42916239 未加载
评论 #42914984 未加载
评论 #42915155 未加载
评论 #42914960 未加载
anymouse1234563 months ago
Please. Just don&#x27;t.<p>Moving state into the global namespace and accessing it directly from that space makes it much more difficult to test, instrument and integrate.<p>Sure, if you&#x27;re building disposable toy software, do whatever is easiest. But if you&#x27;re building software for others to use, at least provide a context struct and pass that around when you can.<p>For those cases where this is challenging or impossible, please sequence your application or library initialization so that these globals are at least fungible&#x2F;assignable at runtime.
stickfigure3 months ago
The problem with global variables is that they imply that there&#x27;s only one of <i>that thing</i>. This assumption - no matter how certain it seems - will inevitably be proven false in any sufficiently long-lived software component.
2d8a875f-39a2-43 months ago
&quot;Guns aren&#x27;t the problem, it&#x27;s all the people pulling triggers.&quot;
jongjong3 months ago
Agreed, global variables are fine up to a certain scale, especially if they&#x27;re only used in the main file. They only really become a problem if you start modifying them from inside different files.<p>The real underlying problem is &#x27;Spooky action at a distance&#x27;; it&#x27;s not an issue that is specific to global variables. If you pass an instance between components by-reference and its properties get modified by multiple components, it can become difficult to track where the state changes originated and that can create very nasty, difficult-to-reproduce bugs. So this can happen even if your code is fully modularized; the issue is that passing instances by reference means that the properties of that instance behave similarly to global variables as they can be modified by multiple different components&#x2F;files (without a single component being responsible for it).<p>That&#x27;s partly where the motivation for functional programming comes from; it forces pass-by-value all the time to avoid all possibility of mutations. The core value is not unique to FP though; it comes from designing components such that they have a simple interface which requires mostly primitive types as parameters. Passing objects is OK too, so long as these objects only represent structured information and their references aren&#x27;t being held onto for future transformation.<p>So for example, you can let components fully encapsulate all the &#x27;instances&#x27; which they manage and only give those parent components INFORMATION about what they have to do (without trying to micromanage their child instances); I avoid passing instances or modules to each other as it generally indicates a leaky abstraction.<p>Sometimes it takes some creativity to find a solution which doesn&#x27;t require instance-passing but when you find such solution, the benefits are usually significant and lasting. The focus should be on message-passing. Like when logging, the code will be easier to follow if all the errors from all the components bubble up to the main file (e.g. via events, streams, callbacks...) and are logged inside the main file because then any developer debugging the code can find the log inside the main file and then trade it down to its originating component.<p>Methods should be given information about what to do, they should not be given the tools to do their job... Like if you catch a taxi in real life, you don&#x27;t bring a jerrycan of petrol and a steering wheel with you to give to the taxi driver. You just provide them with information; the address of your desired destination. You trust that the Taxi driver has all the tools they need to do the job.<p>If you do really want to pass an instance to another instance to manage, then the single-responsibility principle helps limit the complexity and possibility for spooky action. It should only be passed once to initialize and then the receiving component needs to have full control&#x2F;responsibility for that child. I try to avoid as much as possible though.