Consider the following:
Code: Select all
abstract class UOperator extends Object;
function float calculate(float X, float Y)
{
return 0.0;
}
Code: Select all
class SumOperator extends UOperator;
function float calculate(float X, float Y)
{
return X + Y;
}
Code: Select all
class OperatorsMap extends Object;
var private SumOperator sum_operator;
function UOperator getSumOperator()
{
return sum_operator;
}
Code: Select all
class Calculator extends Object;
function float calculate(name Operation, float X, float Y)
{
local OperatorsMap operators_map;
local UOperator u_operator;
operators_map = new class'OperatorsMap';
if (Operation == 'sum') {
u_operator = operators_map.getSumOperator();
}
if (u_operator != None) {
return u_operator.calculate(X, Y);
}
return 0.0;
}
Code: Select all
calculator = new class'Calculator';
number1 = calculator.calculate('sum', 10, 5);
number2 = calculator.calculate('diff', 10, 5);
This code has 2 big problems, both caused by the extreme kind of sanitization checks you advocate.
Can you figure them out?
In programming, there's generally something called a "contract" or "interface" (it has even other names), in which if you say "function F always returns X" you should trust that it will always be so, because that's what the contract that was defined enforces.
If F does not return X for some reason however, your code should not attempt to sanitize the output and continue to run as if nothing happened, the code should "fail" as quick as possible with a clear message of what happened.
By "fail" it can be a crash (natural or through an assertion) or it can be something more graceful as long as the program doesn't internally pretend that everything is just fine.
Do you understand what I am getting at?
Because, the moment an expectation fails to be met, and you keep running the code like absolutely nothing happened, you will endanger yourself into entering an "undefined" state, which will lead to further problems and weird behaviors, which you won't be able to trace back to the real origin and thus you will have a hard time to debug.
Even a more dangerous situation would be when the expectation fails to be met, but you never know about it because "apparently" everything works fine, until it "randomly" stops working.
The latter one is the kind you're actually advocating for, whether you're aware of this yourself or not, because you're so blindly focused in avoiding the logs and crashes themselves, that you don't seem to care at all "why" they happen in the first place, and then end up calling honest developers "dumb", "lazy" and whatnot.
Sanitizing something for the sake of sanitizing is just as bad as never sanitizing at all, there's actually a middle-ground.
Having that said, in UScript itself, like I mentioned previously, the very fact that the vast majority of the references are public and can be freely modified by other actors in runtime, grants that in most cases you just have to account for the fact that the reference might be None, even when spawning actors (not only because of the reasons you highlighted, but even because a valid actor might spawn in a non-valid location).
So what you're doing in this specific case is NOT wrong at all, on the contrary.
Maybe most of the fixes you do are the correct ones in UScript itself, due to its nature, I am not saying otherwise.
It's just the overall idea of what you're advocating is simply not right, specially when it comes to other languages such as C++.
Also, sanitization checks are not free, so there's always a performance hit when doing them, although it's not nearly as significant as the actual problems it causes down the road.
TL\DR: Do checks, yes, but don't do it just for the sake of cleaning the logs.
Like you said, they're just not fancy lines, they serve a purpose, however you're actually treating them as such.