Sujet : Re: else ladders practice
De : david.brown (at) *nospam* hesbynett.no (David Brown)
Groupes : comp.lang.cDate : 12. Nov 2024, 10:43:54
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <vgv80r$1hcrf$1@dont-email.me>
References : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
User-Agent : Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.11.0
On 11/11/2024 20:09, Waldek Hebisch wrote:
David Brown <david.brown@hesbynett.no> wrote:
>
Runtime checks in a function can be useful if you know the calling code
might not be perfect and the function is going to take responsibility
for identifying that situation. Programmers will often be writing both
the caller and callee code, and put temporary debugging and test checks
wherever it is most convenient.
>
But I think being too enthusiastic about putting checks in the wrong
place - the callee function - can hide the real problems, or make the
callee code writer less careful about getting their part of the code
correct.
IME the opposite: not having checks in called function simply delays
moment when error is detected. Getting errors early helps focus on
tricky problems or misconceptions. And motivates programmers to
be more careful
I am always in favour of finding errors at the earliest opportunity - suitable compiler (and even editor/IDE) warnings, strong types, static assertions, etc., are vital tools. Having temporary extra checks at appropriate points in the code are often useful for debugging.
I don't share your feeling about what motivates programmers to be more careful - however, I have no evidence to back that up.
Concerning correct place for checks: one could argue that check
should be close to place where the result of check matters, which
frequently is in called function.
No, there I disagree. The correct place for the checks should be close to where the error is, and that is in the /calling/ code. If the called function is correctly written, reviewed, tested, documented and considered "finished", why would it be appropriate to add extra code to that in order to test and debug some completely different part of the code?
The place where the result of the check /really/ matters, is the calling code. And that is also the place where you can most easily find the error, since the error is in the calling code, not the called function. And it is most likely to be the code that you are working on at the time - the called function is already written and tested.
And frequently check requires
computation that is done by called function as part of normal
processing, but would be extra code in the caller.
It is more likely to be the opposite in practice.
And for much of the time, the called function has no real practical way to check the parameters anyway. A function that takes a pointer parameter - not an uncommon situation - generally has no way to check the validity of the pointer. It can't check that the pointer actually points to useful source data or an appropriate place to store data.
All it can do is check for a null pointer, which is usually a fairly useless thing to do (unless the specifications for the function make the pointer optional). After all, on most (but not all) systems you already have a "free" null pointer check - if the caller code has screwed up and passed a null pointer when it should not have done, the program will quickly crash when the pointer is used for access. Many compilers provide a way to annotate function declarations to say that a pointer must not be null, and can then spot at least some such errors at compile time. And of course the calling code will very often be passing the address of an object in the call - since that can't be null, a check in the function is pointless.
Once you get to more complex data structures, the possibility for the caller to check the parameters gets steadily less realistic.
So now your practice of having functions "always" check their parameters leaves the people writing calling code with a false sense of security - usually you /don't/ check the parameters, you only ever do simple checks that that called could (and should!) do if they were realistic. You've got the maintenance and cognitive overload of extra source code for your various "asserts" and other check, regardless of any run-time costs (which are often irrelevant, but occasionally very important).
You will note that much of this - for both sides of the argument - uses words like "often", "generally" or "frequently". It is important to appreciate that programming spans a very wide range of situations, and I don't want to be too categorical about things. I have already said there are situations when parameter checking in called functions can make sense. I've no doubt that for some people and some types of coding, such cases are a lot more common than what I see in my coding.
Note also that when you can use tools to automate checks, such as "sanitize" options in compilers or different languages that have more in-built checks, the balance differs. You will generally pay a run-time cost for those checks, but you don't have the same kind of source-level costs - your code is still clean, clear, and amenable to correctness checking, without hiding the functionality of the code in a mass of unnecessary explicit checks. This is particularly good for debugging, and the run-time costs might not be important. (But if run-time costs are not important, there's a good chance that C is not the best language to be using in the first place.)