Warning: mysqli::__construct(): (HY000/1203): User howardkn already has more than 'max_user_connections' active connections in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\includes\artfuncs.php on line 21
Failed to connect to MySQL: (1203) User howardkn already has more than 'max_user_connections' active connections
Warning: mysqli::query(): Couldn't fetch mysqli in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\index.php on line 66
Article <vg5351$3pada$1@dont-email.me>
Deutsch   English   Français   Italiano  
<vg5351$3pada$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: Sat, 2 Nov 2024 12:41:20 +0100
Organization: A noiseless patient Spider
Lines: 199
Message-ID: <vg5351$3pada$1@dont-email.me>
References: <3deb64c5b0ee344acd9fbaea1002baf7302c1e8f@i2pn2.org>
 <vg0t3j$2ruor$1@dont-email.me>
 <78eabb4054783e30968ae5ffafd6b4ff2e5a5f17@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>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Sat, 02 Nov 2024 12:41:21 +0100 (CET)
Injection-Info: dont-email.me; posting-host="45c6799a6dc3dae663970e7edcbf3c31";
	logging-data="3975594"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX19vYLMDFbHwJCkW/+53Aq/ZEX8fCh4Qzto="
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:XvzHzcY+4DRA75TnzQCBQOt7QnM=
Content-Language: en-GB
In-Reply-To: <vg3b98$3cc8q$1@dont-email.me>
Bytes: 9029

On 01/11/2024 20:47, Bart wrote:
> On 01/11/2024 18:47, David Brown wrote:
>> On 01/11/2024 19:05, Bart wrote:
>>> On 01/11/2024 17:35, David Brown wrote:
> 
>>>>
>>>> What you have written here is all correct, but a more common method 
>>>> would be to avoid having three printf's :
>>>>
>>>> void shout_a_number(int n) {
>>>>      printf( (const char* []) { "ONE", "TWO", "THREE" } [n] );
>>>> }
>>>>
>>>> That's more likely to match what people would want.
>>>
>>> I was also trying to show that all elements are evaluated, so each 
>>> has to have some side-effect to illustrate that.
>>
>> Fair enough.
>>
>>>
>>> A true N-way-select construct (C only really has ?:) would evaluate 
>>> only one, and would deal with an out-of-range condition.
>>
>> That's a matter of opinion and design choice, rather than being 
>> requirements for a "true" select construct.
> 
> I don't think it's just opinion.

Yes, it is.

I don't disagree that such an "select one of these and evaluate only 
that" construct can be a useful thing, or a perfectly good alternative 
to to an "evaluate all of these then select one of them" construct.  But 
you are completely wrong to think that one of these two is somehow the 
"true" or only correct way to have a selection.

In some languages, the construct for "A or B" will evaluate both, then 
"or" them.  In other languages, it will evaluate "A" then only evaluate 
"B" if necessary.  In others, expressions "A" and "B" cannot have 
side-effects, so the evaluation or not makes no difference.  All of 
these are perfectly valid design choices for a language.

> 
> In general, an if-else-if chain (which was the point of the OP), would 
> evaluate only one branch.

It evaluates all the conditionals down the chain until it hits a "true" 
result, then evaluates the body of the "if" that matches, then skips the 
rest.

(Of course generated code can evaluate all sorts of things in different 
orders, as long as observable behaviour - side-effects - are correct.)

> So would a switch-case construct if sensibly 
> implemented (in C's version, anything goes).
> 

C's switch is perfectly simply and clearly defined.  It is not "anything 
goes".  The argument to the switch is evaluated once, then control jumps 
to the label of the switch case, then evaluation continues from that 
point.  It is totally straight-forward.

You might not like the "fall-through" concept or the way C's switch does 
not quite fit with structured programming.  If so, I'd agree entirely. 
The requirement for lots of "break;" statements in most C switch uses is 
a source of countless errors in C coding and IMHO a clear mistake in the 
language design.  But that does not hinder C's switch statements from 
being very useful, very easy to understand (when used sensibly), and 
with no doubts about how they work (again, when used sensibly).

> The same applies to C's c?a:b operator: only one of a or b is evaluated, 
> not both.

You are conflating several ideas, then you wrote something that you 
/know/ is pure FUD about C's switch statements.  So writing "The same 
applies" makes no sense.

You are, of course, correct that in "c ? a : b", "c" is evaluated first 
and then one and only one of "a" and "b".

> 
> (This also why implementing if, switch, ?: via functions, which lots are 
> keen to do in the reddit PL forum, requires closures, lazy evaluation or 
> other advanced features.)
> 

Yes, you'd need something like that to implement such "short-circuit" 
operators using functions in C.  In other languages, things may be 
different.

> 
>>   You are free to choose the rules you want for your own language, but 
>> you are not free to dictate what you think the rules should be for 
>> others.  (You are welcome to /opinions/, of course.)
>>
>>>
>>> (In my implementations, a default/else branch value must be provided 
>>> if the whole thing is expected to return a value.)
>>>
>>
>> OK, if that's what you want.  My preference, if I were putting 
>> together what /I/ thought was an idea language for /my/ use, would be 
>> heavy use of explicit specifications and contracts for code, so that a 
>> default/else branch is either disallowed (if there the selection 
>> covers all legal values) or required (if the selection is 
>> abbreviated).  A default value "just in case" is, IMHO, worse than 
>> useless.
> 
> All such multiway constructs in my languages (there are 4, one of which 
> the job of both 'if' and  C's ?:) have an optional else branch. A 
> missing 'else' has an notional 'void' type.
> 
> But it becomes mandatory if the whole thing returns a value, to satisfy 
> the type system, because otherwise it will try and match with 'void'.
> 

Your language, your choice.  I'd question the whole idea of having a 
construct that can evaluate to something of different types in the first 
place, whether or not it returns a value, but that's your choice.

> SOMETHING needs to happen when none of the branches are executed; what 
> value would be returned then? The behaviour needs to be defined. You 
> don't want to rely on compiler analysis for this stuff.

In my hypothetical language described above, it never happens that none 
of the branches are executed.

Do you feel you need to write code like this?

const char * flag_to_text_A(bool b) {
	if (b == true) {
		return "It's true!";
	} else if (b == false) {
		return "It's false!";
	} else {
		return "Schrödinger's cat has escaped!";
	}
}


When you have your "else" or "default" clause that is added for 
something that can't ever happen, how do you test it?

> 
> In C on the other hand, the ':' of '?:' is always needed, even when it 
> is not expected to yield a value. Hence you often see this things like 
> this:
> 
>     p == NULL ? puts("error"): 0;

Given that the tertiary operator chooses between two things, it seems 
fairly obvious that you need two alternatives to choose from - having a 
choice operator without at least two choices would be rather useless.

I can't say I have ever seen the tertiary operator used like this. 
There are a few C programmers that like to code with everything as 
expressions, using commas instead of semicolons, but they are IMHO 
mostly just being smart-arses.  It's a lot more common to write :

	if (!p) puts("error");

And in most cases, you'd have a return when "p" is not valid, or make 
the rest of the function part of the conditional rather than continuing 
with a null "p".

> 
> Here, gcc at least, also requires the types of the two branches to 
> match, even though the whole construct yields no common value. 

========== REMAINDER OF ARTICLE TRUNCATED ==========