Would it break backward compatibility for C to add a feature like this
from Python? Namely, the ability to check if a value lies in an interval:
def valid_char(c) :
"is integer c the code for a valid Unicode character." \
" This excludes surrogates."
return \
(
0 <= c <= 0x10FFFF
and
not (0xD800 <= c < 0xE000)
)
#end valid_char
On 04/06/2024 09:14, Lawrence D'Oliveiro wrote:
Would it break backward compatibility for C to add a feature like this
from Python? Namely, the ability to check if a value lies in an interval:
def valid_char(c) :
"is integer c the code for a valid Unicode character." \
" This excludes surrogates."
return \
(
0 <= c <= 0x10FFFF
and
not (0xD800 <= c < 0xE000)
)
#end valid_char
Do you mean, could C treat "a <= x <= b" as "(a <= x) && (x <= b)"
without breaking existing code? The answer is no, C treats it as the expression "(a <= x) <= b". So you would be changing the meaning of
existing C code. I think it's fair to say there is likely to be very
little existing correct and working C code that relies on the current interpretation of such expressions, but the possibility is enough to
rule out such a change ever happening in C. (And it would also
complicate the grammar a fair bit.)
<https://c-faq.com/expr/transitivity.html>
Would it break backward compatibility for C to add a feature like this
from Python? Namely, the ability to check if a value lies in an interval:
def valid_char(c) :
"is integer c the code for a valid Unicode character." \
" This excludes surrogates."
return \
(
0 <= c <= 0x10FFFF
and
not (0xD800 <= c < 0xE000)
)
#end valid_char
On 2024-06-04 08:58:53 +0000, David Brown said:
On 04/06/2024 09:14, Lawrence D'Oliveiro wrote:
Would it break backward compatibility for C to add a feature like this
from Python? Namely, the ability to check if a value lies in an
interval:
def valid_char(c) :
"is integer c the code for a valid Unicode character." \
" This excludes surrogates."
return \
(
0 <= c <= 0x10FFFF
and
not (0xD800 <= c < 0xE000)
)
#end valid_char
Do you mean, could C treat "a <= x <= b" as "(a <= x) && (x <= b)"
without breaking existing code? The answer is no, C treats it as the
expression "(a <= x) <= b". So you would be changing the meaning of
existing C code. I think it's fair to say there is likely to be very
little existing correct and working C code that relies on the current
interpretation of such expressions, but the possibility is enough to
rule out such a change ever happening in C. (And it would also
complicate the grammar a fair bit.)
<https://c-faq.com/expr/transitivity.html>
That does not prevet from doing the same with a different syntax.
The main difference is that in the current C syntax that cannot be
said without mentioning c twice. In the example program C would
require that c is mentioned four times but the shown Python code
only needs it mentioned twice. An ideal syntax woult only mention
it once, perhaps
return c in 0 .. 0xD7FF, 0xE000 .. 0x10FFFF ;
or
return c : [0 .. 0xD800), [0xE000 .. 0x10FFFF] ;
or something like that, preferably so that no new reserved word is
needed.
On 04/06/2024 11:13, Mikko wrote:
On 2024-06-04 08:58:53 +0000, David Brown said:
On 04/06/2024 09:14, Lawrence D'Oliveiro wrote:
Would it break backward compatibility for C to add a feature like this >>>> from Python? Namely, the ability to check if a value lies in an
interval:
def valid_char(c) :
"is integer c the code for a valid Unicode character." \
" This excludes surrogates."
return \
(
0 <= c <= 0x10FFFF
and
not (0xD800 <= c < 0xE000)
)
#end valid_char
Do you mean, could C treat "a <= x <= b" as "(a <= x) && (x <= b)"
without breaking existing code? The answer is no, C treats it as the
expression "(a <= x) <= b". So you would be changing the meaning of
existing C code. I think it's fair to say there is likely to be very
little existing correct and working C code that relies on the current
interpretation of such expressions, but the possibility is enough to
rule out such a change ever happening in C. (And it would also
complicate the grammar a fair bit.)
<https://c-faq.com/expr/transitivity.html>
That does not prevet from doing the same with a different syntax.
The main difference is that in the current C syntax that cannot be
said without mentioning c twice. In the example program C would
require that c is mentioned four times but the shown Python code
only needs it mentioned twice. An ideal syntax woult only mention
it once, perhaps
return c in 0 .. 0xD7FF, 0xE000 .. 0x10FFFF ;
or
return c : [0 .. 0xD800), [0xE000 .. 0x10FFFF] ;
or something like that, preferably so that no new reserved word is
needed.
Sure, you can always add new things to a language if they would
previously have been syntax errors or constraint errors. But is there a
use for it?
It is fine if you have a language that has good support for lists, sets, ranges, and other higher-level features - then an "in" keyword is a
great idea. But C is not such a language, and that kind of feature
would be well outside the scope of the language.
It would be easy enough to write a macro "in_range(a, x, b)" that would
do the job. It is even easier, and more productive, that you simply
write the "valid_char" function and use it, if that's what you need.
On 04/06/2024 11:13, Mikko wrote:
On 2024-06-04 08:58:53 +0000, David Brown said:
On 04/06/2024 09:14, Lawrence D'Oliveiro wrote:
Would it break backward compatibility for C to add a feature like this >>>> from Python? Namely, the ability to check if a value lies in an interval: >>>>
def valid_char(c) :
"is integer c the code for a valid Unicode character." \
" This excludes surrogates."
return \
(
0 <= c <= 0x10FFFF
and
not (0xD800 <= c < 0xE000)
)
#end valid_char
Do you mean, could C treat "a <= x <= b" as "(a <= x) && (x <= b)"
without breaking existing code?� The answer is no, C treats it as the
expression "(a <= x) <= b".� So you would be changing the meaning of
existing C code.� I think it's fair to say there is likely to be very
little existing correct and working C code that relies on the current
interpretation of such expressions, but the possibility is enough to
rule out such a change ever happening in C.� (And it would also
complicate the grammar a fair bit.)
<https://c-faq.com/expr/transitivity.html>
That does not prevet from doing the same with a different syntax.
The main difference is that in the current C syntax that cannot be
said without mentioning c twice. In the example program C would
require that c is mentioned four times but the shown Python code
only needs it mentioned twice. An ideal syntax woult only mention
it once, perhaps
�return c in 0 .. 0xD7FF, 0xE000 .. 0x10FFFF ;
or
�return c : [0 .. 0xD800), [0xE000 .. 0x10FFFF] ;
or something like that, preferably so that no new reserved word is
needed.
Sure, you can always add new things to a language if they would
previously have been syntax errors or constraint errors. But is there
a use for it?
It is fine if you have a language that has good support for lists,
sets, ranges, and other higher-level features - then an "in" keyword is
a great idea. But C is not such a language, and that kind of feature
would be well outside the scope of the language.
It would be easy enough to write a macro "in_range(a, x, b)" that would
do the job. It is even easier, and more productive, that you simply
write the "valid_char" function and use it, if that's what you need.
operators as a concept are bad enough;
On 2024-06-04 08:58:53 +0000, David Brown said:
On 04/06/2024 09:14, Lawrence D'Oliveiro wrote:
Would it break backward compatibility for C to add a feature like this
from Python? Namely, the ability to check if a value lies in an
interval:
def valid_char(c) :
"is integer c the code for a valid Unicode character." \
" This excludes surrogates."
return \
(
0 <= c <= 0x10FFFF
and
not (0xD800 <= c < 0xE000)
)
#end valid_char
Do you mean, could C treat "a <= x <= b" as "(a <= x) && (x <= b)"
without breaking existing code? The answer is no, C treats it as the
expression "(a <= x) <= b". So you would be changing the meaning of
existing C code. I think it's fair to say there is likely to be very
little existing correct and working C code that relies on the current
interpretation of such expressions, but the possibility is enough to
rule out such a change ever happening in C. (And it would also
complicate the grammar a fair bit.)
<https://c-faq.com/expr/transitivity.html>
That does not prevet from doing the same with a different syntax.
The main difference is that in the current C syntax that cannot be
said without mentioning c twice. In the example program C would
require that c is mentioned four times but the shown Python code
only needs it mentioned twice. An ideal syntax woult only mention
it once, perhaps
return c in 0 .. 0xD7FF, 0xE000 .. 0x10FFFF ;
or
return c : [0 .. 0xD800), [0xE000 .. 0x10FFFF] ;
or something like that, preferably so that no new reserved word is
needed.
On 04/06/2024 12:02, David Brown wrote:
On 04/06/2024 11:13, Mikko wrote:
On 2024-06-04 08:58:53 +0000, David Brown said:
On 04/06/2024 09:14, Lawrence D'Oliveiro wrote:
Would it break backward compatibility for C to add a feature like this >>>>> from Python? Namely, the ability to check if a value lies in an
interval:
def valid_char(c) :
"is integer c the code for a valid Unicode character." \
" This excludes surrogates."
return \
(
0 <= c <= 0x10FFFF
and
not (0xD800 <= c < 0xE000)
)
#end valid_char
Do you mean, could C treat "a <= x <= b" as "(a <= x) && (x <= b)"
without breaking existing code? The answer is no, C treats it as
the expression "(a <= x) <= b". So you would be changing the
meaning of existing C code. I think it's fair to say there is
likely to be very little existing correct and working C code that
relies on the current interpretation of such expressions, but the
possibility is enough to rule out such a change ever happening in
C. (And it would also complicate the grammar a fair bit.)
<https://c-faq.com/expr/transitivity.html>
That does not prevet from doing the same with a different syntax.
The main difference is that in the current C syntax that cannot be
said without mentioning c twice. In the example program C would
require that c is mentioned four times but the shown Python code
only needs it mentioned twice. An ideal syntax woult only mention
it once, perhaps
return c in 0 .. 0xD7FF, 0xE000 .. 0x10FFFF ;
or
return c : [0 .. 0xD800), [0xE000 .. 0x10FFFF] ;
or something like that, preferably so that no new reserved word is
needed.
Sure, you can always add new things to a language if they would
previously have been syntax errors or constraint errors. But is there
a use for it?
It is fine if you have a language that has good support for lists,
sets, ranges, and other higher-level features - then an "in" keyword
is a great idea. But C is not such a language, and that kind of
feature would be well outside the scope of the language.
I disagree. I have a script language where 'in' works with all sorts of
data types, and where ranges like a..b and sets like [a..b, c, d, e] are actual types.
Yet I also introduced 'in' into my systems language, even though it is
very restricted:
if a in b..c then
if a in [b, c, d] then
This is limited to integer types. The set construct here doesn't allow
ranges (it could have done). Neither the range or set is a datatype - it
just syntax. (I can't do range r := 1..10.)
It is incredibly useful:
if c in [' ', '\t', '\n'] then ... # whitespace
if b in 0..255 then
if b in u8.bounds then # alternative
Not to forget:
if x = y = 0 then # both x and y are zero
It doesn't need the full spec of the higher level language.
It would be easy enough to write a macro "in_range(a, x, b)" that
would do the job. It is even easier, and more productive, that you
simply write the "valid_char" function and use it, if that's what you
need.
Yes it would be easier - to provide an ugly, half-assed solution that
everyone will write a different way (I would use (x, a, b) for example),
and which can go wrong as soon as someone writes (a, x(), b).
That's the problem with the macro scheme, it stops the language properly evolving.
On 04/06/2024 13:23, bart wrote:
On 04/06/2024 12:02, David Brown wrote:
It is fine if you have a language that has good support for lists,
sets, ranges, and other higher-level features - then an "in" keyword
is a great idea. But C is not such a language, and that kind of
feature would be well outside the scope of the language.
I disagree. I have a script language where 'in' works with all sorts
of data types, and where ranges like a..b and sets like [a..b, c, d,
e] are actual types.
C is not a script language.
Yet I also introduced 'in' into my systems language, even though it is
very restricted:
if a in b..c then
if a in [b, c, d] then
This is limited to integer types. The set construct here doesn't allow
ranges (it could have done). Neither the range or set is a datatype -
it just syntax. (I can't do range r := 1..10.)
Adding such a feature to your own personal language, for your own
personal use, is easy enough (relative to the rest of the work involved
in designing your own personal language and making tools for it, which
is of course no small feat). Adding it to C with its standards,
existing code, toolchains, additional tools, developers, etc., is a
whole different kettle of fish.
It would be easy enough to write a macro "in_range(a, x, b)" that
would do the job. It is even easier, and more productive, that you
simply write the "valid_char" function and use it, if that's what you
need.
Yes it would be easier - to provide an ugly, half-assed solution that
You and I are British - the term is "half-arsed" :-)
On 04/06/2024 14:24, David Brown wrote:
On 04/06/2024 13:23, bart wrote:
On 04/06/2024 12:02, David Brown wrote:
It is fine if you have a language that has good support for lists,
sets, ranges, and other higher-level features - then an "in" keyword
is a great idea. But C is not such a language, and that kind of
feature would be well outside the scope of the language.
I disagree. I have a script language where 'in' works with all sorts
of data types, and where ranges like a..b and sets like [a..b, c, d,
e] are actual types.
C is not a script language.
Yet I also introduced 'in' into my systems language, even though it
is very restricted:
if a in b..c then
if a in [b, c, d] then
This is limited to integer types. The set construct here doesn't
allow ranges (it could have done). Neither the range or set is a
datatype - it just syntax. (I can't do range r := 1..10.)
Adding such a feature to your own personal language, for your own
personal use, is easy enough (relative to the rest of the work
involved in designing your own personal language and making tools for
it, which is of course no small feat). Adding it to C with its
standards, existing code, toolchains, additional tools, developers,
etc., is a whole different kettle of fish.
I was responding to your comment:
"and that kind of feature would be well outside the scope of the language."
I think it can suit that level of language if you avoid being too
ambitious.
I agree it is not practical to apply to C at this point, not without
making it ugly or unwieldy enough that people might as well use existing solutions.
(Such a feature also aids simpler non-optimising compilers. Take these examples that all do the same thing:
if a <= f() and f() <= c then fi
if a <= f() <= c then fi
if f() in a..c then fi
If the two f() calls in the first example were considered common subexpressions, I don't have the means in my compiler to detect that
that and evaluate them just once.
In the other two examples, the language lets you express that directly.
Even for a simpler 'b in a..c' example, it is easier to generate more efficient code, and do that more efficiently too than building something
up only to tear it down again.)
It would be easy enough to write a macro "in_range(a, x, b)" that
would do the job. It is even easier, and more productive, that you
simply write the "valid_char" function and use it, if that's what
you need.
Yes it would be easier - to provide an ugly, half-assed solution that
You and I are British - the term is "half-arsed" :-)
I'm catering for a wider readership.
(Actually I'm not quite considered British enough to be allowed in the upcoming election.)
David Brown <[email protected]> writes:
On 04/06/2024 13:23, bart wrote:
It is incredibly useful:
if c in [' ', '\t', '\n'] then ... # whitespace
if (strpbrk(c, " \t\n") != NULL) it_is_whitespace.
On 04/06/2024 13:23, bart wrote:
It is incredibly useful:
if c in [' ', '\t', '\n'] then ... # whitespace
If it were considered useful enough, it could be standardised in the C >library. If it is not useful enough to standardise in the library, it
is certainly not useful enough to put in the language itself.
On Tue, 4 Jun 2024 16:58:43 +0100
bart <[email protected]> wrote:
On 04/06/2024 16:27, Scott Lurndal wrote:
David Brown <[email protected]> writes:
On 04/06/2024 13:23, bart wrote:
It is incredibly useful:
if c in [' ', '\t', '\n'] then ... # whitespace
if (strpbrk(c, " \t\n") != NULL) it_is_whitespace.
That doesn't do the same thing. In my example, c is a character, not
a string.
Will that be be better?
if (memchr(" \t\n", c, 3) != NULL)
On 04/06/2024 16:27, Scott Lurndal wrote:
David Brown <[email protected]> writes:
On 04/06/2024 13:23, bart wrote:
It is incredibly useful:
if c in [' ', '\t', '\n'] then ... # whitespace
if (strpbrk(c, " \t\n") != NULL) it_is_whitespace.
That doesn't do the same thing. In my example, c is a character, not
a string.
i think that we need not worsen the matter with new ternary operators.
On Tue, 4 Jun 2024 11:41:54 -0000 (UTC), Blue-Maned_Hawk wrote:
i think that we need not worsen the matter with new ternary operators.
These are not ternary operators.
On 05/06/2024 00:12, Lawrence D'Oliveiro wrote:
On Tue, 4 Jun 2024 11:41:54 -0000 (UTC), Blue-Maned_Hawk wrote:
i think that we need not worsen the matter with new ternary operators.
These are not ternary operators.
So what are they?
I've implemented them several times, and found they really need to be
treated as a special kind of n-ary opterator.
That's the problem with the macro scheme, it stops the language properly evolving.
On Wed, 5 Jun 2024 00:22:36 +0100, bart wrote:
On 05/06/2024 00:12, Lawrence D'Oliveiro wrote:
On Tue, 4 Jun 2024 11:41:54 -0000 (UTC), Blue-Maned_Hawk wrote:
i think that we need not worsen the matter with new ternary operators.
These are not ternary operators.
So what are they?
A special case in the syntax rules for the comparison operators <https://docs.python.org/3/reference/expressions.html#comparisons>.
I've implemented them several times, and found they really need to be
treated as a special kind of n-ary opterator.
Remember, Python allows users to define custom overloads for the standard operators. For comparisons, these functions always take two operands, and
the compiler takes care of invoking them correctly to handle interval comparisons.
if a = b then end # universal if a = b < c then end
On Thu, 6 Jun 2024 19:48:42 +0100, bart wrote:
if a = b then end # universal if a = b < c then end
Really?? You allow that?
The 'a=b' (that's equality)
Lawrence D'Oliveiro <[email protected]d> writes:
On Fri, 7 Jun 2024 01:52:34 +0100, bart wrote:
The 'a=b' (that's equality)
Not in C it isn’t.
Of course not. You snipped the part where Bart very clearly said that
he was talking about his own scripting language.
Lawrence D'Oliveiro <[email protected]d> writes:
On Fri, 7 Jun 2024 01:52:34 +0100, bart wrote:
The 'a=b' (that's equality)
Not in C it isn’t.
Of course not. You snipped the part where Bart very clearly said that
he was talking about his own scripting language. And we're talking
about a proposed new C feature, so I have no problem with references to
other languages.
And there's precedent in other languages (Python, as Bart already
pointed out) for `a == b < c` being equivalent to `a == b && b < c`,
but with b evaluated only once.
*If* C were to adopt chained comparisons, I would have no problem
with `a == b < c` being supported with the obvious meaning.
I dislike arbitrary restrictions. (Though the fact that == and
< have different precedences would have to be resolved somehow.)
In principle it could quietly change the behavior of existing code,
but it's likely that most such code was already wrong. I don't
advocate making such a change, and I don't think it's likely to
happen, I wouldn't object to it.
C++ provides flexible
operator overloading combined with a poverty of available operators, so
the relational operators <, >, <= and >= are sometimes used for
completely different purposes, similar to the >> and << operators.
Chaining relational operators would complicate this significantly, I
think.
However, 'a > b <= c' is not clear.
To me, this possibility, along with the confusion it would cause,
totally outweighs any potential convenience of chained comparisons.
Even in a new language, I would not want to see chained relational
operators unless you had a strict requirement that relational operators evaluate to a boolean type with no support for relational operators
between booleans, and no support for comparison or other operators
between booleans and other types.
And even then, what is "a == b == c"
supposed to mean, or "a != b != c" ?
I
have never found them helpful in Python coding, and I can't imagine them being of any interest in my C code.
David Brown <[email protected]> writes:
On 07/06/2024 05:53, Keith Thompson wrote:[...]
There is also the C++ compatibility question. C++ provides flexible
operator overloading combined with a poverty of available operators,
so the relational operators <, >, <= and >= are sometimes used for
completely different purposes, similar to the >> and <<
operators. Chaining relational operators would complicate this
significantly, I think. If C++ adopted the feature it would be a mess
to support overloading, and if they did not, "a < b < c" in C and C++
would be valid but with completely different semantics. Neither
option is good.
I mentioned earlier that someone did a study of open source C++ code and found no occurrences of things like "a < b < c", except for 4 cases that
were intended to be chained but would behave incorrectly. I presume
that this study would have covered overloaded operators.
To me, this possibility, along with the confusion it would cause,
totally outweighs any potential convenience of chained comparisons. I
have never found them helpful in Python coding, and I can't imagine
them being of any interest in my C code.
I agree. I wouldn't mind being able to use the feature, and I think
I've actually used it in Python, but its lack isn't a big problem.
Even in a new language, I would not want to see chained relational
operators unless you had a strict requirement that relational
operators evaluate to a boolean type with no support for relational
operators between booleans, and no support for comparison or other
operators between booleans and other types.
In Python, all comparison operators (<, >, ==, >=, <=, !=, is, is not,
in, not in) have the same precedence, and chained operations are
specified straightforwardly. They evaluate to a bool result. Boolean
values can be compared (False < True), which doesn't seem to cause any problems.
https://docs.python.org/3/reference/expressions.html#comparisons
And even then, what is "a
== b == c" supposed to mean, or "a != b != c" ?
"a == b && b == c", and "a != b && b != c", respectively, except that b
is only evaluated once.
On Fri, 7 Jun 2024 11:28:23 +0100, bart wrote:
However, 'a > b <= c' is not clear.
One thing it would have been handy to have is some way of saying
b < a or b > c
in a chained comparison somehow. In other words, “not (a < b < c)” without the negation and need for the parentheses (and
correspondingly for the obvious usages of “<=” and “>=”).
On 07/06/2024 10:22, David Brown wrote:
So the restrictions I would suggest are:
* Not mixing <, <= with >, >= in the same chain (any angle brackets
should point the same way)
* Not allowing != in the chain.
Such a chain also requires that all 6 (or 5) operators have the same precedence, as you can't have 'a = b <= c' mean 'a = (b <= c)'.
I
have never found them helpful in Python coding, and I can't imagine them being of any interest in my C code.
The most common uses for me are comparing that N terms are equal (here = means equality):
if x.tag = y.tag = ti64
if a = b = 0
I also used them for range-checking:
if a <= b <= c
until I introduced 'if b in a..c' for that purpose. (However I would
still need 'a <= b <= c' for floating point.)
What I might then suggest for C, as a first step, is to allow only
chained '==' comparisons. That avoids those ambiguous cases, and also
the problem with mixed precedence, while still providing a handy new
feature.
On 07/06/2024 12:28, bart wrote:
On 07/06/2024 10:22, David Brown wrote:
; Ithem
have never found them helpful in Python coding, and I can't imagine
being of any interest in my C code.
The most common uses for me are comparing that N terms are equal (here
= means equality):
if x.tag = y.tag = ti64
if a = b = 0
These do not correspond to what you want to say.
If someone has balloons, and you want to check that they have 2 red
balloons and two yellow balloons, you do start off by checking if the
number of red balloons is the same as the number of yellow balloons, and
then that the number of yellow balloons is 2.
Code syntax should, where practical, reflect its purpose and intent. You should therefore write (adjusting to C, Python, or your own syntax as desired) :
if red_balloons == 2 and yellow_balloons == 2 ...
If you don't want to write the "magic number" 2 twice, you give it a name :
expected_balloons = 2
if red_balloons == expected_balloons
and yellow_balloons == expected_balloons...
I also used them for range-checking:
if a <= b <= c
until I introduced 'if b in a..c' for that purpose. (However I would
still need 'a <= b <= c' for floating point.)
Using "in" and a range or interval syntax would usually be clearer, and closer to the intended meaning, IMHO.
Both of these chained shortcuts are used in mathematics, so they are not unfamiliar. But in writing mathematics, compared to programming, you
have a lot more freedom to expect the reader to interpret things
sensibly, and vastly more freedom in layout while also having an
incentive to keep things compact. Good or common mathematical syntax
does not necessarily translate directly to good programming syntax.
What I might then suggest for C, as a first step, is to allow only
chained '==' comparisons. That avoids those ambiguous cases, and also
the problem with mixed precedence, while still providing a handy new
feature.
On 07/06/2024 12:28, bart wrote:
On 07/06/2024 10:22, David Brown wrote:
So the restrictions I would suggest are:
* Not mixing <, <= with >, >= in the same chain (any angle brackets
should point the same way)
* Not allowing != in the chain.
I think these are good ideas.
David Brown <[email protected]> writes:
On 07/06/2024 11:55, Keith Thompson wrote:
David Brown <[email protected]> writes:If "c" is a boolean, some might think the "natural" interpretation of
On 07/06/2024 05:53, Keith Thompson wrote:[...]
"a == b == c" is "(a == b) == c" - it is the current semantics in C.
Some people may think that "a != b != c" should be interpreted as "(a
!= b) & (b != c) & (a != c)".
Yes, some people might be wrong.
It's one thing to make a rigid definition of the meaning in a
language, picking a consistent set of rules of precedence and syntax.
It is another thing to make sure it matches up with the
interpretations people have from normal mathematics, natural language,
and other programming languages. When there is a mismatch, you need
good reasons to accept the syntax as a good language design idea - the
more likely the misunderstanding, the stronger reasons you need.
To me, the potential misunderstandings of including != in chains is
far too high in comparison to the meagre benefits. The use of ==
could be clear in some situations (combined with strong type checking
to help catch mistakes) but not others. I could see a chain of a mix
of < and <= making sense, or of > and >=, and occasionally being
useful. I don't think there is a point in allowing more than that.
After all, if all you need is to avoid evaluating "b" more than once,
you can just do:
auto const b_ = b;
There are two separate issues here.
One is adding chained comparisons to C. We both agree that this is impractical because it would silently change the meaning of valid code.
(Changing the meaning of old code isn't likely to be much of an issue,
but any new code using the feature would quietly change behavior when compiled under older C standards or when ported to C++.)
The other (arguably off-topic) is providing chained comparisons in other languages.
Python does this well, in my opinion. All comparison
operators have the same precedence, and the semantics of chained
comparisons are defined straightforwardly. There are no arbitrary restrictions, so you can write things that some people might find ugly
or confusing (if you have a language that bans ugly code, I'd like to
see it). The meaning of `a =< b > c` or `a != b == c` is perfectly clear once you understand the rules, and it doesn't change if any of the
operands are of type bool. `a != b != c` *doesn't* mean
`a != b and a != c and b != c`. (If you want to test whether all three
are unequal to each other, you can write `a != b != c != a`, though that evalutes `a` twice.)
On 07/06/2024 12:17, David Brown wrote:
On 07/06/2024 12:28, bart wrote:
On 07/06/2024 10:22, David Brown wrote:
; Iimagine them
have never found them helpful in Python coding, and I can't
being of any interest in my C code.
The most common uses for me are comparing that N terms are equal
(here = means equality):
if x.tag = y.tag = ti64
if a = b = 0
These do not correspond to what you want to say.
If someone has balloons, and you want to check that they have 2 red
balloons and two yellow balloons, you do start off by checking if the
number of red balloons is the same as the number of yellow balloons,
and then that the number of yellow balloons is 2.
("you don't"?)
That's not quite the intent of my examples, which is:
(1) That x.tag/y.tag or a/b are equal to each other
(2) That they also have a particular value
Code syntax should, where practical, reflect its purpose and intent.
You should therefore write (adjusting to C, Python, or your own syntax
as desired) :
if red_balloons == 2 and yellow_balloons == 2 ...
Here that connection is lost. You might infer it, but you don't know
whether, at some point, the program could be changed to require 3 red balloons, while still needing 2 yellow ones.
Or someone could just write 3 by mistake. By repeating such terms, there
is more opportunity for mistakes, and the connection between terms is
looser.
Here is another real example, first written in static code (not in C;
I've shortened 'sample' to avoid line-wrap):
if hdr.hsamp[2] = hdr.vsamp[2] = hdr.hsamp[3] = hdr.vsamp[3] and
(hdr.hsamp[1] <= 2 and hdr.vsamp[1] <= 2) then
pimage := loadcolour(fs, hdr.hsamp[1], hdr.vsamp[1])
and here in dynamic code:
(vsample1, vsample2, vsample3) := hdr.vsample
(hsample1, hsample2, hsample3) := hdr.hsample
...
if hsample2 = vsample2 = hsample3 = vsample3 and
(hsample1 <= 2 and vsample1 <=2 ) then
....
Both check that 4 terms are identical, but there is no specific value
they have to be.
(It would have been nice to avoid that repetition of '2' in that second
test, but that's more difficult to achieve. There, hsample1/vsample1
don't need to have the same value.
It's expressible as something like 'reduce(and, map(<=, (a, b), 2)' but that's using a sledgehammer just to avoid that duplicate '2'. It's not
suited to lower-level code either.)
On 07/06/2024 14:20, bart wrote:
On 07/06/2024 12:17, David Brown wrote:
On 07/06/2024 12:28, bart wrote:
On 07/06/2024 10:22, David Brown wrote:
; Iimagine them
have never found them helpful in Python coding, and I can't
being of any interest in my C code.
The most common uses for me are comparing that N terms are equal
(here = means equality):
if x.tag = y.tag = ti64
if a = b = 0
These do not correspond to what you want to say.
If someone has balloons, and you want to check that they have 2 red
balloons and two yellow balloons, you do start off by checking if the
number of red balloons is the same as the number of yellow balloons,
and then that the number of yellow balloons is 2.
("you don't"?)
Yes, sorry about that!
That's not quite the intent of my examples, which is:
(1) That x.tag/y.tag or a/b are equal to each other
(2) That they also have a particular value
If that is your intent, then fair enough. But I think that is an
unusual intent.
Of course, I have no idea what "x.tag" or "ti64"
represent,
and if I had, the code might have made more sense to me.
At least for the second example, if you did not have chaining equality,
I think you would have preferred to write :
if (a = 0) and (b = 0) ...
rather than
if (a = b) and (b = 0) ...
If that is indeed the case, then IMHO the chaining version is less clear.
Code syntax should, where practical, reflect its purpose and intent.
You should therefore write (adjusting to C, Python, or your own
syntax as desired) :
if red_balloons == 2 and yellow_balloons == 2 ...
Here that connection is lost. You might infer it, but you don't know
whether, at some point, the program could be changed to require 3 red
balloons, while still needing 2 yellow ones.
Or someone could just write 3 by mistake. By repeating such terms,
there is more opportunity for mistakes, and the connection between
terms is looser.
Sure. If this is a risk, use a separate constant (with appropriate
name) for the numbers you want, and write that name rather than the
number 2.
There comes a point when a function called "all_equal", or "rising", is
the right choice. How those functions might be implemented is a matter
of language, and also whether you want them to work with a variable
parameter list or over arrays, lists, slices, or whatever the language supports. High-level functions like map and reduce could be part of
this, along with folds. For example, in C++ 17 (which supports a fold syntax), you might write :
template <typename H1>
constexpr bool rising(H1)
{
return true;
}
template <typename H1, typename H2, typename ... T>
constexpr bool rising(H1 head1, H2 head2, T... tail)
{
return head1 <= head2 && rising(head2, tail...);
}
Then
rising(a, b, c, d)
is interpreted as
a <= b && rising(b, c, d)
and so on.
I don't think it is fair to claim particular ways of writing these
things are always clearer, or better, or uglier, or unclear - it will
depend on the rest of the language, and how the code is used. But in general I think it helps to write code that follows the logic of what
the writer really means, rather than alternative constructions that give
the same result.
On 09/06/2024 12:26, David Brown wrote:
On 07/06/2024 14:20, bart wrote:
On 07/06/2024 12:17, David Brown wrote:
If that is your intent, then fair enough. But I think that is an
unusual intent.
Really, checking that A and B both have the same value X is that unusual?
I don't think it is fair to claim particular ways of writing these
things are always clearer, or better, or uglier, or unclear - it will
depend on the rest of the language, and how the code is used. But in
general I think it helps to write code that follows the logic of what
the writer really means, rather than alternative constructions that
give the same result.
Using function-like syntax is OK when you have the same operator between multiple terms. 'rising' could have '<' or '<='.
All-equal would have the same operator too, but it looks clunkier, and a
bit over-the-top:
a = b 2 terms
all_equal(a, b, c) 3 terms using your feature
a = b = c 3 terms using chained ops
rising(a, b, c) Using your other feature
a <= b <= c Using the same chained-op feature
Your solution requires a heavyweight language feature. It also looks
like it will generate a lot of intermediate code that will need a
heavyweight optimiser to tear down again.
| Sysop: | Keyop |
|---|---|
| Location: | Huddersfield, West Yorkshire, UK |
| Users: | 715 |
| Nodes: | 16 (2 / 14) |
| Uptime: | 143:53:13 |
| Calls: | 12,089 |
| Calls today: | 2 |
| Files: | 15,000 |
| Messages: | 6,517,477 |