Live data from Hacker News

Global variables are not the problem

codestyleandtaste.com

131–140 of 165 posts

Re: Global variables are not the problem

#131

I find the concept of a context structure passed as the first parameter to all your functions with all your "globals" to be very compelling for this sort of stuff.

This plus immutable data is what makes doing web apps in Elixir using Phoenix so nice. There is a (demi-)god "%Conn" structure passed as the first parameter that middleware and controller actions can update (by returning a new struct). The %Conn structure is then used in the final step of the request cycle to return data for the request.

For non-web work genservers in Elixir have immutable state that is passed to every handler. This is "local" global state and since genservers guarantee ordering of requests via the mailbox handlers can update state also by returning a new state value and you never have race conditions.

Re: Global variables are not the problem

#132

Earlier quoted context omitted.

In this case, yes. Its scope should be the lowest necessary scope. Does JS provide static variables in functions? If not, then that forces you to lift it to some other scope like file or module scope or the surrounding function or class if that's viable.

> Does JS provide static variables const f = (() => { let cnt = 0; return () => console.log("cnt", cnt); })(); :-)

That abbreviation of count is an interesting choice. ;-)

Re: Global variables are not the problem

#133

I find the concept of a context structure passed as the first parameter to all your functions with all your "globals" to be very compelling for this sort of stuff.

Or every occurrence of the singleton pattern (except for when it's the flyweight pattern)

Re: Global variables are not the problem

#134
post #116

Earlier quoted context omitted.

How is a globally-scoped closure not a global variable?

Because there is no intent, need or reason to vary it. Nearly everything in RAM is technically a global variable to someone who is keen enough. Programming depends on a sort-of honour system not to treat things like variables if it is hinted that they shouldn't and it doesn't make sense to. Otherwise we can all start making calls to scanmem & friends.

Right but closing over a state with a function and giving that closure a name seems to quack like a duck to me. Maybe it's just because I'm a scheme guy and we're more upfront about this.

Re: Global variables are not the problem

#135
post #84
post #59

Earlier quoted context omitted.

Or caches! I have gotten shit before for using global variables, and sometimes that is justified, but I almost never see anyone given shit over treating Redis as a big ol’ global map.

When it comes to "patterns" and "anti-patterns", double standards are common.

Yeah. Honestly, I think Redis is very often overused and likely makes stuff slower.

If your application is only running on one computer, and especially if it's only running in one process, you will likely get better performance using a big ol' thread-safe hashmap that's global/singleton. You pay basically no latency cost, no (de)serialization costs, and the code is likely going to be simpler.

I've seen people who seem to think that just inserting stuff into Redis will somehow automatically make their code better, only for the code to actually become slower because of network latency.

I've also seen people use Redis as a way to have global variables because it's too hard to figure out how to scope stuff correctly.

Re: Global variables are not the problem

#136

Earlier quoted context omitted.

In this case, yes. Its scope should be the lowest necessary scope. Does JS provide static variables in functions? If not, then that forces you to lift it to some other scope like file or module scope or the surrounding function or class if that's viable.

> Does JS provide static variables const f = (() => { let cnt = 0; return () => console.log("cnt", cnt); })(); :-)

Yep, like I said if it doesn't have it then you have to lift the variable to another scope:

> If not, then that forces you to lift it to ... the surrounding function

Re: Global variables are not the problem

#138
post #129

I think this article broadens the definition of global variable and then says "Look, the things I added to the definition aren't bad, so global variables aren't always bad." If you just look at what people normally mean by global variable, then I don't think the article changes minds on that.

To make it worse: "Look, the things I added to the definition aren't bad in this specific language and use-case, so global variables are not the problem". To me, the author either has a very narrow field of focus and honestly forgets about all the other use-cases, practicalities and perspectives, or they choose to ignore it just to fire up a debate. In any case, these constructs are only true for JavaScript (in node.…

> If I were to port this to Rust, first, the borrow checker would catch the described bugs and not allow me to write them in the first place. But secondly, if I really insist on something global that I need to mutate or share between threads, I can do so, but would be explicitly required to choose a type (Mutex, RwLock, with Arc or something) so that a) I have thought about the problem and b) chose something that I know to work for my case.

Agreed. Not the specifics, as I don't know Rust, but it makes sense.

Re: Global variables are not the problem

#139

Earlier quoted context omitted.

I’m having a difficult time understanding the practical difference between watching an internal state object vs an external one. Surely if you can observe one you can just as easily observe the other, no? Surely if you can mutate a state object and pass it, its state can get mutated equally deep within the codebase no different than a global, no? What am I missing here? To me this just sounds like a discipline issue…

> To me this just sounds like a discipline issue rather than a semantic one. Using an explicit parameter obviates the need for discipline since you can mechanically trace where the value was set. In contrast, global values can lead to action at a distance via implicit value changes. For example, if you have two separate functions in the same thread, one can implicitly change a value used by the other if it's thread-l…

I'm sorry I just think we're going in circles.

A few posts up I clearly said use encapsulation and then mutate state via known methods. These would be just as traceable in your IDE/debugger.

Further, I have also repeatedly mentioned both module-level and thread-level "globals".

And I understand how concurrency works.

Take care.

Re: Global variables are not the problem

#140

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. For example, global variables have drawbacks, but so does re-writin…

Depends a bit on the language.

A global variable in a language with parallel operation is often a terrible idea. The problem with globals and parallel operations is they are an inherent risk for race conditions that can have wild consequences.

In some languages, for example, a parallel write to a field is not guaranteed to be consistent. Let's assume in the above example `counter` was actually represented with 2 bytes. If two threads write an increment to it without a guard, there is no guarantee which thread will win the upper byte and which will win the lower byte. Most of the time it will be fine, but 1 in 10k there can be a bizarre counter leap (forwards or backwards) that'd be almost impossible to account for.

Now imagine this global is tucked away in a complex library somewhere and you've got an even bigger problem. Parallel calls to the library will just sometimes fail in ways that aren't easy to explain and, unfortunately, can only be fixed by the callee with a library wrapping synchronization construct. Nobody wants to do that.

All of these problems are masked by a language like Javascript. Javascript is aggressively single threaded (Everything is ran in a mutex!). Sure you can do concurrent things with callbacks/async blocks, but you can't mutate any application state from 2 threads. That makes a global variable work in most cases. It only gets tricky if you are dealing with a large amount of async while operating on the global variable.

Post reply on HN