Deutsch   English   Français   Italiano  
<vb77mc$3bu07$2@dont-email.me>

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

Path: ...!feeds.phibee-telecom.net!2.eu.feeder.erje.net!feeder.erje.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: David Brown <david.brown@hesbynett.no>
Newsgroups: comp.lang.c
Subject: Re: Code guidelines
Date: Tue, 3 Sep 2024 16:49:48 +0200
Organization: A noiseless patient Spider
Lines: 147
Message-ID: <vb77mc$3bu07$2@dont-email.me>
References: <vb6v1t$3b5mb$1@dont-email.me> <vb726n$3b4rq$1@dont-email.me>
 <vb736j$3b5mb$2@dont-email.me> <vb75c5$3bu07$1@dont-email.me>
 <vb76us$3bntp$2@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Tue, 03 Sep 2024 16:49:49 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="93d7d6b8e3b40fe75b60c4526d162769";
	logging-data="3536903"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX1/UdOnCKr5bpjHaTo90M158owMul+kjUs4="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.11.0
Cancel-Lock: sha1:4HwXP6u8Bml/6DMWVMPFLl14Q1M=
Content-Language: en-GB
In-Reply-To: <vb76us$3bntp$2@dont-email.me>
Bytes: 6797

On 03/09/2024 16:37, Thiago Adams wrote:
> On 03/09/2024 11:10, David Brown wrote:
>> On 03/09/2024 15:33, Thiago Adams wrote:
>>> On 03/09/2024 10:16, David Brown wrote:
>>>> On 03/09/2024 14:22, Thiago Adams wrote:
>>
>>>> I am of the opinion that if something is clearly specified, you make 
>>>> sure it is true when you are responsible for it - and then you can 
>>>> assume it is true when you use the results.  It makes no sense to me 
>>>> to do something, and then immediately check that it is done.
>>>>
>>>> Whenever possible, these specifications should be in code, not 
>>>> comments - using whatever tools and extra features you have 
>>>> available for use. Macros and conditional compilation help make code 
>>>> more portable, and can also let you turn compile-time assumptions 
>>>> into run-time checks during debugging.
>>>>
>>>
>>> Yes, this contract "function don't returns null" is very 
>>> straightforward for the caller and for the implementer.
>>>
>>> The contract implementation can be checked inside function 
>>> implementation. (One place to check the contract implementation)
>>> The contract usage, is checked in each caller, but very straightforward.
>>>
>>> On the other hand, struct members have much more places where the 
>>> contract can be broken. Each function that have a non const access to 
>>> user->name could break the contract implementation.
>>> The risk is much bigger compared with the return case.
>>
>> You are asking about "guidelines".  Yes, it is possible for code to 
>> break specifications.  The guideline is "don't do that".
>>
> 
> The guidelines are more about the usage of runtime checks, are they 
> required? optional? etc.. when to use etc...
> 

The guideline is "follow the specifications".  Then it is obvious that 
run-time checks are not required unless you are dealing with code that 
does not follow the specifications.

Now, as you note below, code under development might not follow the 
specifications - that is why it is useful to do this sort of thing with 
macros that support adding run-time checks during development or 
debugging.  Standard C "assert" is a poor man's version of this.

> 
>> If you are mixing untrusted code with trusted code, then you have to 
>> check the incoming data just like you do with data from external 
>> sources.  But most functions are not at such boundaries.
> 
> yes ..agree.
> 
>>>
>>> So I think it may make sense to have redundant runtime checks, but it 
>>> must be clear the the "compile time contract" is not that one.
>>>
>>>
>>> For instance:
>>>
>>> The first sample my create confusion (is name optional?)
>>>
>>> void f(struct user* user)
>>> {
>>>       if (user->name && strcmp(user->name, "john") == 0)
>>>       {
>>>          //...
>>>       }
>>>   }
>>>
>>> But :
>>> void f(struct user* user)
>>> {
>>>       assert(user->name);
>>>       if (user->name && strcmp(user->name, "john") == 0)
>>>       {
>>>          //...
>>>       }
>>>   }
>>>
>>> would show redundancy but making clear the contract still "name 
>>> should not be null"
>>>
>>
>> No, redundant runtime checks are not helpful.  If they are redundant, 
>> they are by definition a waste of effort - either run-time efficiency, 
>> or developer efficiency, or both.  And they are a maintenance mess as 
>> changes have to be applied in multiple places.
>>
> 
> But we know , when the code is new (under development) the contract may 
> not be so clear or change very frequently.
> 

Then it is even worse to have redundant checks - when they are 
inconsistent, you have no idea what is going on or what /should/ be 
going on.


> 
>>      void f(struct user* user)
>>      {
>>          if (!user->name) __builtin_unreachable();
>>          if (strcmp(user->name, "john") == 0) {
>>              //...
>>          }
>>      }
>>
>> Now it is /really/ clear that user->name should not be null, and 
>> instead of two run-time checks doing the same thing, there are no 
>> run-time costs and the compiler may even be able to optimise more from 
>> the knowledge that the pointer is not null.
>>
>> In practice I use a macro called "Assume" here, which will give a hard 
>> compile-time error if the compiler can that the assumption is false.  
>> It also supports optional run-time checks depending on a #define'd 
>> flag (normally set as a -D compiler flag), as an aid to debugging.
>>
>> Write things clearly, once, in code.
>>
>> If the code is boundary code, then you need a check - but then a 
>> simple null pointer check is unlikely to be sufficient.  (What if the 
>> pointer is not null, but not a valid pointer?  Or it does not point to 
>> a string of a suitable length, with suitable character set, etc.?)
>>
> 
> The macro I need is something like
> 
> "I know this check is redundant, but I will add it anyway" "this check 
> is redundant but according with the contract"

If a check is redundant, and the compiler can see that, the extra check 
will be eliminated by optimisation.  So you are wasting developer time 
for nothing.

> 
> assert/assume is more
> 
> "trust me compiler, this is what happens" someone else is checking this 
> we don't need to check again.
> 

That is not what "assert" is, but it is roughly what my "Assume" is. 
And yes, that is what you should be aiming for in the code.