Should I use global static FString variables?

Hello,

In the project I’m working on, devs use global const FString variables like so:
In the MyClass.h file:

namespace FABCMyClassConstants
{
	extern const FString HttpPostVerb;
	extern const FString ContentTypeHeaderName;
	extern const FString ApplicationJsonContentType;
	extern const FString ContentEncodingHeaderName;
	extern const FString GzipContentEncoding;
}

And in the MyClass.cpp file:

namespace FABCMyClassConstants
{
	const FString HttpPostVerb = TEXT("POST");
	const FString ContentTypeHeaderName = TEXT("Content-Type");
	const FString ApplicationJsonContentType = TEXT("application/json");
	const FString ContentEncodingHeaderName = TEXT("Content-Encoding");
	const FString GzipContentEncoding = TEXT("gzip");
}

Which makes using them pretty verbose and hard to read:

Request->SetVerb(FABCMyClassConstants::HttpPostVerb);
Request->SetHeader(FABCMyClassConstants::ContentTypeHeaderName, FABCMyClassConstants::ApplicationJsonContentType);

Compared to a simpler:

Request->SetVerb(TEXT("POST"));
Request->SetHeader(TEXT("Content-Type"), TEXT("application/json"));

Now, I have read that it avoids constructing FString objects repeatedly, but it really hinders readability in my opinion.

I have also read some of the Epic source code and couldn’t find anything similar.

Should I oppose this?

Think about how much time you can save in a situation where you need to change the text in your global variable. You will do it in one move.
Or you will have to change ALL the places where you use the variable value.

All of them are only used in one place and not very prone to change. So if that’s the only benefit, I take readability over this any day.

In my opinion, from a readability standpoint, using global/static variables also adds clarity. Using them, you are LITERALLY using the same thing.

For example, Epic uses Static Const FName to denote the pin type. These haven’t changed since at least 4.27, but using them lets you know that the pin type is LITERALLY this one, and not another with the same value. It definitely adds to readability.

Yeah I don’t agree. It adds a LOT of code with these constant namespace blocks that tend to become huge and you need to go back and forth between the code you’re reading and these separate declarations to know what value the string variables actually hide.

For example:

Body->SetStringField(FABCMyClassConstants::EventNamespaceKey, FABCMyClassConstants::GameEventNamespace);

What is the event namespace value? Is it pascal case, is it camel case?

Every line like this, you need to go back to the top of the file to get your answers. That is not what I call readable. You also add 3 lines instead of 1 for every one of these variables.

Now I agree that if a given variable is used in a lot of places, you should try to centralize it. But I don’t agree in the case where you have several variables that are only used once.

Use “using namespace” to get rid of NameSpace::

That barely solves anything. If anything, that makes it even less readable because now you don’t know where the variable comes from…

Example:

Body->SetStringField(EventNameKey, EventName);
Body->SetStringField(EventNamespaceKey, GameEventNamespace);

EventName is a local method variable here and GameEventNamespace is a global constant. You need more context to understand these lines of code, it is the opposite of readable.

My consideration is not about readability, it’s more about performance here. It would seem like using an const FString variable would be more effective because it avoids creating FString variables over and over.

But then I checked Epic’s code and I could not find this done anywhere. If it’s ever used, I would bet it’s for centralization purposes, not performance. And in the case of a widely used variable I fully agree that it should be make more globally available.

But it seems very inefficient to allocate a new FString every time, is it not a consideration? If yes, why would Epic ignore this completely? I do not believe their devs are incompetent.

How often is this code executed ? I don’t think performance is such a problem here (as far as usage of FString is concerned) unless you notice frame drops while executing this. I would just go with the readability over trying to squeeze as much performance as you can.

In shipping build the compiler will optimize those strings.

Can you elaborate this exact part, this is very interesting to me.

We have different configurations like Debug, Development and shipping, particularly in shipping the compiler can make some adjustment to optimize your code depending on the platform, these optimizations can minimize execution time, memory usage etc.

Sometimes the compiler can decide to bake certain strings in the binary as an optimization.

This is what I need details on. Do you have some documentation on this process or some more details please?