| Deutsch English Français Italiano |
|
<vgibf8$2l858$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: Bart <bc@freeuk.com>
Newsgroups: comp.lang.c
Subject: Re: else ladders practice
Date: Thu, 7 Nov 2024 12:23:04 +0000
Organization: A noiseless patient Spider
Lines: 122
Message-ID: <vgibf8$2l858$1@dont-email.me>
References: <3deb64c5b0ee344acd9fbaea1002baf7302c1e8f@i2pn2.org>
<vg2g37$37mh3$1@dont-email.me> <6724CFD2.4030607@grunge.pl>
<vg2llt$38ons$1@dont-email.me>
<2491a699388b5891a49ef960e1ad8bb689fdc2ed@i2pn2.org>
<b681ee05856e165c26a5c29bf42a8d9d53843d6d@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> <vge7bt$1o57r$1@dont-email.me>
<vgfvne$25kug$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Thu, 07 Nov 2024 13:23:04 +0100 (CET)
Injection-Info: dont-email.me; posting-host="ec686777c96cc376bc9818100d47f072";
logging-data="2793640"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18lwmXbUJ4Ej4bXQCoToPf6"
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:BoWE0mEMmtX5aF2tJirvDpXxqVg=
Content-Language: en-GB
In-Reply-To: <vgfvne$25kug$1@dont-email.me>
Bytes: 6325
On 06/11/2024 14:50, David Brown wrote:
> On 05/11/2024 23:48, Bart wrote:
>> On 05/11/2024 13:29, David Brown wrote:
>>> int small_int_sqrt(int x) {
>>> if (x == 0) return 0;
>>> if (x < 4) return 1;
>>> if (x < 9) return 2;
>>> if (x < 16) return 3;
>>> unreachable();
>>> }
> "unreachable()" is a C23 standardisation of a feature found in most
> high-end compilers. For gcc and clang, there is
> __builtin_unreachable(), and MSVC has its version.
So it's a kludge. Cool, I can create one of those too:
func smallsqrt(int x)int =
if
elsif x=0 then 0
elsif x<4 then 1
elsif x<9 then 2
elsif x<16 then 3
dummyelse int.min
fi
end
'dummyelse' is a special version of 'else' that tells the compiler that
control will (should) never arrive there. ATM it does nothing but inform
the reader of that and to remind the author. But later stages of the
compiler can choose not to generate code for it, or to generate
error-reporting code.
(A couple of things about this: the first 'if' condition and branch can
be omitted; it starts at elsif. This removes the special-casing for the
first of an if-elsif-chain, so to allow easier maintenance, and better
alignment.
Second is that, unlike your C, the whole if-fi construct is a single
expression term that yields the function return value. Hence the need
for all branches to be present and balanced regarding their common type.
This could have been handled internally (compiler adds 'dummyelse <empty
value for type>'), but I think it's better that it is explicit (user
might forget to add that branch).
That int.main is something I sometimes use for in-band signalling. Here
that is the value -9223372036854775808 so it's quite a wide band!
Actually it is out-of-band it the user expects only result with an i32
range.
BTW your example lets through negative values; I haven't fixed that.)
>> Getting that right will satisfy both the language (if it cared more
>> about such matters than C apparently does), and the casual reader
>> curious about how the function contract is met (that is, supplying
>> that promised return int type if or when it returns).
>
> C gets it right here. There is no need for a return type when there is
> no return
There is no return for only half the function! A function with a return
type is a function that CAN return. If it can't ever return, then make
it a procedure.
Take this function where N can never be zero; is this the right way to
write it in C:
int F(int N) {
if (N==0) unreachable();
return abc/N; // abc is a global with value 100
}
If doesn't look right. If I compile it with gcc (using
__builtin_unreachable), and call F(0), then it crashes. So it doesn't do
much does it?!
> indeed, trying to force some sort of type or "default" value
> would be counterproductive. It would be confusing to the reader, > add
> untestable and unexecutable source code,
But it IS confusing, since it quite clearly IS reachable. There's a
difference between covering all possible values of N, so that is
genuinely is unreachable, and having code that COULD be reachable.
> Let's now look at another alternative - have the function check for
> validity, and return some kind of error signal if the input is invalid.
> There are two ways to do this - we can have a value of the main return
> type acting as an error signal, or we can have an additional return value.
....
> All in all, we have a significant costs in various aspects, with no real
> benefit, all in the name of a mistaken belief that we are avoiding
> undefined behaviour.
This is all a large and complex subject. But it's not really the point
of the discussion.
I'm not talking about what happens when running a program, but what
happens at compilation, and satisfying the needs of the language.
C here is less strict in being happy to have parts of a function body as
no-go areas where various requirements can be ignored, like a function
with a designed return type T, being allowed to return without
satisfying that need.
Here, you demostrated bolted-on hacks that are not part of the language,
like the snappy __builtin_unreachable (the () are apparently optional).
I can't see however that it does much.
It is a fact C as a language allows this:
T F() {} // T is not void
(I've had to qualify T - point number 9 in procedures vs. function.)
All that C says is that control flow running into that closing },
without encountering a 'return x', is UB.
IMV, sloppy. My language simply doesn't allow it.