January 26, 2022

On Wednesday, 26 January 2022 at 07:51:30 UTC, rempas wrote:

>

On Tuesday, 25 January 2022 at 12:07:31 UTC, Ola Fosheim Grøstad wrote:

>

Because the program is larger, there are more locations that could mutate the global state. ("reason" ≈ "prove correct")

Yeah but what if it makes sense for these places to mutate it? For example, I'm making a parser for my language and each different statement will be parsed from a function that will be in a different file. It makes sense for those files to be able to mutate some global variables.

>
  1. globals are singletons, it becomes difficult to have multiple instance if you later regret having only one instance.

  2. because you need to use locking correctly to prevent multiple threads from mutating the state at once and then you have to prove that your locking strategy is does not lead to starvation or deadlocks.

I don't know about most of this terms and I know only a little about multi-threading programming. So thank you, I will make my research and this info will come in handy!

>

I don't understand what you are trying to say here.

The global variable should be local to the object file. The accessor functions can be globally accessible.

Actually the example I made with the parser will explain that too. I want some specific files to be able to access the global variables. If they are only local to a file then they don't help me a lot and I still have to use pointers to modify that specific data.

>

Passing one pointer isn't particularly expensive. What (non-TLS) globals save you on some CPUs are registers and time spent on allocation.

Thanks! Why talking about allocations tho? We will not need to allocate any memory to pass a pointer to a function and then deference it. Of course if you think that you will push it to the stuck in your main function and then you will call all the other functions in the top.

>

For instance, using globals can make sense in embedded programming on tiny CPUs with very little RAM.

Well yeah! However, embedded programming is an advanced topic so I suppose different rules apply there anyways...

>

https://dlang.org/spec/attribute.html#gshared

Thanks a lot!!

For a compiler, I'd think each step shouldn't modify state but rather you pass the current state to the next step.

Ex. first you parse lexical information and you pass that information to the semantic analysis, which then passes that information on etc.

You should only "modify" the current localized state IMHO. Ex. the current statement being parsed can and should be modified, but you shouldn't be able to modify anything else like suddenly modifying the compiler configurations in the middle of semantic analysis etc.

I think it's especially important for compilers to not use global state because you want to be able to localize every single issue right away to a specific unit in the compiler.

January 26, 2022

On Wednesday, 26 January 2022 at 08:49:02 UTC, bauss wrote:

>

I think it's especially important for compilers to not use global state because you want to be able to localize every single issue right away to a specific unit in the compiler.

I would think that you sometimes can gain a bit of performance by making the symbol table global (as you don't have to rebuild it for every source file), but it can become rather large so there is a trade-off.

January 26, 2022

On Tuesday, 25 January 2022 at 14:29:32 UTC, Steven Schveighoffer wrote:

>

That's not the reason. Global variables are hard to control and review. That is, if a variable is global, how do you know it's not misused? The point of not using global variables is to reduce the surface area of the program that needs review to ensure it's correctly used.

Yeah, I understand know how this can be very important with bigger and more complex apps where a lot of developers will work or with Library APIs.

>

In some cases, they make sense, and in those cases, I'd recommend at least guarding the direct access to the variable through properties so you can control how it's used.

What do you mean "properties"? I suppose not struct/class properties right?

>
  1. Declare the variables in a function, then run your algorithms inside inner functions. They all now have access to the variable. I'm surprised at how many complex problems and APIs become super-straightforward when you start using local functions (even templated ones).

That's actually a really great way of doing it but it will be a mess if you have the huge functions that I do. This will work great with small algorithms. Or you could use string enums to insert code in place. A lot of things to consider!

>
  1. Enclose the data and methods in a struct, even if that struct is a struct inside a function. This is a necessity if you have mutually recursive functions, since a local function cannot call another local function that hasn't been defined yet.

-Steve

This is what I'll probably do. Not only because of the problem you mentioned but because it will allow my to use functions in separate files like I normally would!

Thanks a lot for your time man!

January 26, 2022

On Tuesday, 25 January 2022 at 14:44:01 UTC, bachmeier wrote:

>

I don't think it's common that you need global variables in D. If you want to share a variable among several functions, use a struct. But if a global is the best solution, use the global.

Yeah, it turns out that for most of my variables, I should use a struct instead. But there are some variables that I will keep global because I want almost everything to be able to access them and they will be immutable. These variables will also have one instance and this will never change so it makes more sense for them to be global.

>

If you've ever had the joy of working with FORTRAN 77 or earlier versions of FORTRAN (back when it was in all caps) you understand why working with globals can be a traumatic experience. For instance, multiple functions in multiple files will sometimes change the same global variable.

I started getting interested in programing in 2020 (even tho I had some prior experience with Python in school but this doesn't count) so I didn't had the joy to work with any version of FORTRAN. Fun fact: I thought that FORTRAN (do we really need to write it in capital letters?) is an ancient language but I made a research and found out that it is still updated!!!

January 26, 2022

On Wednesday, 26 January 2022 at 09:04:27 UTC, Ola Fosheim Grøstad wrote:

>

On Wednesday, 26 January 2022 at 08:49:02 UTC, bauss wrote:

>

I think it's especially important for compilers to not use global state because you want to be able to localize every single issue right away to a specific unit in the compiler.

I would think that you sometimes can gain a bit of performance by making the symbol table global (as you don't have to rebuild it for every source file), but it can become rather large so there is a trade-off.

Well you could pass the symbol table to each step rather than each step accessing the symbol table themselves.

But of course it all depends on your situation and what your goals are.

It makes sense to use globals in some cases and in others it don't.

I think the problem with globals is just how easy you can screw up using them, but when used right they can be useful.

January 26, 2022

On Tuesday, 25 January 2022 at 15:47:12 UTC, Ali Çehreli wrote:

>

On 1/25/22 01:53, rempas wrote:

>

people dislike global variables

The situation is much better in D because I suspect what you call global is D's module-scope and thread-local.

(Note: I don't want to argue whether thread-local by default was a good decision or not but I certainly take full advantage of the ease of thread-local variables in D.)

So, module-scope variables are just fine: std.parallelism uses a default ThreadPool object, std.stdio functions use stdout, in this case a truly global object, etc.

>

When I have a variable that I must pass down to 5-6
functions, I find it much easier to make it global rather
than having it
been passed in all the functions that need it.

I've used that method once, which I mentioned at this point during a presentation:

https://youtu.be/dRORNQIB2wA?t=2946

Both you and I realize that a module is an object and in our case there is a single object of it. That works.

When you need more than one object (more than one context), then you move all those variables to a user-defined type and they become proper member variables.

>

global variables can mess me up

Otherwise, as everybody else told, global variables can be very dangerous:

https://www.safetyresearch.net/toyota-unintended-acceleration-and-the-big-bowl-of-spaghetti-code/

That report mentions "thousands of global variables", all of which I bet started as "what can go wrong?"

Ali

As always, thank for the great info Ali! Wish you an amazing day!

January 26, 2022

On Tuesday, 25 January 2022 at 21:34:57 UTC, Dukc wrote:

>

Because purity is convenient. When I call a function, let's say field.initializeUnit(12, 15) it's so much nicer and tidier if I can rest assured it won't affect anything else than field, and if I know it acts the exact same way every time, when the arguments are similar.

Now consider if field was a global variable. Okay, initializeUnit(12, 15) is shorter than field.initializeUnit(12, 15). But I have to set the field I want to manipulate in advance, theField = /*whatever*/. And when reading code that acts like this, I do not know what affects what without peeking what each of the called functions do. Did the initializeUnit use theField or thatOtherField? With the pure version I can instantly see it's the field variable I'm using. The non-pure version is much uglier and harder to read after all, despite having a shorter argument list.

Yeah, of course. In your example, it is actually stupid to use a global variable and it doesn't makes sense.

>

If the argument lists get lengthy, it is sometimes worth to collect the argument sets into structs or classes that have most of the needed data in one place. You might also consider the with statement. But globals just plain blow.

Yep, like other said! I'm doing that right now! Thanks!

January 26, 2022

On Tuesday, 25 January 2022 at 23:28:36 UTC, forkit wrote:

>

// ---

module test;
import std;

int x = 0;

void main()
{
writeln(foo);
}

int foo()
{
int x = 10;

if(x) // ooh. you sure this was your intention??
    return x;
else
    return .x;

}

// ---

What ".x" returns? Also this example is not very practical. You could do the same if you had passed "x" as a function parameter?

January 26, 2022
On Wednesday, 26 January 2022 at 11:24:34 UTC, rempas wrote:
> On Tuesday, 25 January 2022 at 23:28:36 UTC, forkit wrote:
>> // ---
>>
>> module test;
>> import std;
>>
>> int x = 0;
>>
>> void main()
>> {
>>     writeln(foo);
>> }
>>
>> int foo()
>> {
>>     int x = 10;
>>
>>     if(x) // ooh. you sure this was your intention??
>>         return x;
>>     else
>>         return .x;
>> }
>>
>> // ---
>
> What ".x" returns? Also this example is not very practical. You could do the same if you had passed "x" as a function parameter?

so you asked for an example where you could slip up using a global variable.

well, that was an example.

you have a local variable the same name as global variable.. you mistyped... and... boom!
January 26, 2022
On Wednesday, 26 January 2022 at 11:29:31 UTC, forkit wrote:
>
oh. what is actually going on in foo is irrelevant of course.

foo does nothing of any relevance.

the point I was making, was about having a global variable with the same name as as a local variable, could 'potentially' slip you up.