Deutsch   English   Français   Italiano  
<vgv80r$1hcrf$1@dont-email.me>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!eternal-september.org!feeder2.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: David Brown <david.brown@hesbynett.no>
Newsgroups: comp.lang.c
Subject: Re: else ladders practice
Date: Tue, 12 Nov 2024 10:43:54 +0100
Organization: A noiseless patient Spider
Lines: 105
Message-ID: <vgv80r$1hcrf$1@dont-email.me>
References: <3deb64c5b0ee344acd9fbaea1002baf7302c1e8f@i2pn2.org>
 <vg2ttn$3a4lk$1@dont-email.me> <vg33gs$3b8n5$1@dont-email.me>
 <vg358c$3bk7t$1@dont-email.me> <vg37nr$3bo0c$1@dont-email.me>
 <vg3b98$3cc8q$1@dont-email.me> <vg5351$3pada$1@dont-email.me>
 <vg62vg$3uv02$1@dont-email.me> <vgd3ro$2pvl4$1@paganini.bofh.team>
 <vgd6jh$1hmjc$1@dont-email.me> <vgds97$2r682$1@paganini.bofh.team>
 <vgdvfj$1m6ho$1@dont-email.me> <vgplgk$757j$1@paganini.bofh.team>
 <vgqk1h$edif$2@dont-email.me> <vgtkoi$igod$1@paganini.bofh.team>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Tue, 12 Nov 2024 10:43:56 +0100 (CET)
Injection-Info: dont-email.me; posting-host="a5429ea85c799ed95a4268769dd7f276";
	logging-data="1618799"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX1+GDaNxykAiXRszHk0MHkY73cYtS7We/0Q="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.11.0
Cancel-Lock: sha1:Gtr0hyhQnXDE77xRDW0QjkteZP8=
Content-Language: en-GB
In-Reply-To: <vgtkoi$igod$1@paganini.bofh.team>
Bytes: 6923

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.)