Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Signed unsigned mismatch?

132 views
Skip to first unread message

Rick C. Hodgin

unread,
Sep 18, 2018, 11:18:49 AM9/18/18
to
I have this code (simplified for this example):

#include <stdio.h>
#include <stdint.h>

unsigned char a = 2;
unsigned char b = 2;
unsigned char c = 2;
uint32_t d = 5;

int main(int argc, char* argv[])
{
if (a + b + c > d)
printf("...\n");

return(0);
}

If I use godbolt.org and compare the MSVC x86 2015 and 2017
versions with "/W4 /TC" (all warnings, compile as C code),
then I get these messages. The same comes up without "/TC":

https://godbolt.org

MSVC:
warning C4018: '>': signed/unsigned mismatch

If I try it with GCC 8.2 with "-Wall -x c" I get no errors
(compile in C mode). But if I take off the "-x c" I get
this error:

GCC 8.2:
warning: comparison of integer expressions of different
signedness: 'int' and 'uint32_t' {aka 'unsigned int'}
[-Wsign-compare]

Why are an "unsigned char" and a uint32_t being seen as a
different signedness? If I trace uint32_t to its definition,
it's "unsigned int" in MSVC.

Is it a compiler bug in MSVC?

--
Rick C. Hodgin

james...@alumni.caltech.edu

unread,
Sep 18, 2018, 11:58:30 AM9/18/18
to
If UCHAR_MAX < INT_MAX (which is likely, but not guaranteed), then expressions of type unsigned char get promoted to 'int' (4.5p1). It's "int" and "unsigned int" which have different signedness. This can result in undefined behavior if expressions of that type overflow, something that would not happen if those types had not been promoted.

Rick C. Hodgin

unread,
Sep 18, 2018, 12:05:12 PM9/18/18
to
Why would the promotion from unsigned type x not be to unsigned type
y of a greater bit size rather than signed type y of a greater bit
size?

That seems contrary to what one looking in on this would expect.

--
Rick C. Hodgin

Mr Flibble

unread,
Sep 18, 2018, 12:47:31 PM9/18/18
to
Satan invented fossils yes?

I don't help egregious misogynistic homophobic bigoted cunts who think
religion excuses them for being egregious misogynistic homophobic bigoted
cunts and I wish others wouldn't either so fuck off and die you egregious
misogynistic homophobic bigoted cunt.

/Flibble

--
"Suppose it’s all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I’d say, bone cancer in children? What’s that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It’s not right, it’s utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That’s what I would say."

james...@alumni.caltech.edu

unread,
Sep 18, 2018, 1:03:56 PM9/18/18
to
That depends entirely upon what expectations you bring with you;
early implementors choose two different approaches, but the C
committee selected only one of them for inclusion in C89. All
later versions of the C and C++ standards have simply ratified
that decision and made minor improvements in the wording. Since
the decision was made 30 years ago, and huge amounts of code have
been written that expect this rule to be followed, the chance that
someone might convince either committee to change it's mind are
quite negligible, and in fact you would have to convince both
committees. Here's what the C Rationale has to say about this issue:

Between the publication of K&R and the development of C89, a
serious divergence had occurred among implementations in the
evolution of integer promotion rules. Implementations fell into
two major camps which may be characterized as unsigned preserving
and value preserving. The difference between these approaches
centered on the treatment of unsigned char and unsigned short
when widened by the integer promotions, but the decision had an
impact on the typing of constants as well (see §6.4.4.1).
The unsigned preserving approach calls for promoting the two
smaller unsigned types to unsigned int. This is a simple rule,
and yields a type which is independent of execution environment.
The value preserving approach calls for promoting those types to
signed int if that type can properly represent all the values of
the original type, and otherwise for promoting those types to
unsigned int. Thus, if the execution environment represents short
as something smaller than int, unsigned short becomes int;
otherwise it becomes unsigned int.
Both schemes give the same answer in the vast majority of cases,
and both give the same effective result in even more cases in
implementations with two’s-complement arithmetic and quiet
wraparound on signed overflow—that is, in most current
implementations. In such implementations, differences between the
two only appear when these two conditions are both true:

1. An expression involving an unsigned char or unsigned short
produces an int-wide result in which the sign bit is set, that
is, either a unary operation on such a type, or a binary
operation in which the other operand is an int or “narrower”
type.
2. The result of the preceding expression is used in a context in
which its signedness is significant:
• sizeof(int) < sizeof(long) and it is in a context where it must
be widened to a long type, or
• it is the left operand of the right-shift operator in an
implementation where this shift is defined as arithmetic, or
• it is either operand of /, %, <, <=, >, or >=.

In such circumstances a genuine ambiguity of interpretation
arises. The result must be dubbed questionably signed, since a
case can be made for either the signed or unsigned
interpretation.
Exactly the same ambiguity arises whenever an unsigned int
confronts a signed int across an operator, and the signed int has
a negative value. Neither scheme does any better, or any worse,
in resolving the ambiguity of this confrontation. Suddenly, the
negative signed int becomes a very large unsigned int, which may
be surprising, or it may be exactly what is desired by a
knowledgeable programmer. Of course, all of these ambiguities can
be avoided by a judicious use of casts.
One of the important outcomes of exploring this problem is the
understanding that high-quality compilers might do well to look
for such questionable code and offer (optional) diagnostics, and
that conscientious instructors might do well to warn programmers
of the problems of implicit type conversions.
The unsigned preserving rules greatly increase the number of
situations where unsigned int confronts signed int to yield a
questionably signed result, whereas the value preserving rules
minimize such confrontations. Thus, the value preserving rules
were considered to be safer for the novice, or unwary,
programmer. After much discussion, the C89 Committee decided in
favor of value preserving rules, despite the fact that the UNIX
C compilers had evolved in the direction of unsigned preserving.

QUIET CHANGE IN C89
A program that depends upon unsigned preserving arithmetic
conversions will behave differently, probably without complaint.
This was considered the most serious semantic change made by the
C89 Committee to a widespread current practice.

The Standard clarifies that the integer promotion rules also
apply to bit-fields.

Rick C. Hodgin

unread,
Sep 18, 2018, 1:29:04 PM9/18/18
to
Interesting. FWIW, I think the C committee got it wrong. The
source type should drive the promotion, and if there is another
consideration (such as unsigned to sign across an operator),
then a second promotion should be given in that case, to the
next largest signed on both sides of the operator.

This is what CAlive does, by the way. To me, it's the only way
that makes sense when you view data as data, and view it being
processed from the point of view of what a human being would ex-
pect the answer to be.

--
Rick C. Hodgin

james...@alumni.caltech.edu

unread,
Sep 18, 2018, 2:37:00 PM9/18/18
to
On Tuesday, September 18, 2018 at 1:29:04 PM UTC-4, Rick C. Hodgin wrote:
...
> Interesting. FWIW, I think the C committee got it wrong.

What a surprise.

Rick C. Hodgin

unread,
Sep 18, 2018, 2:49:10 PM9/18/18
to
Wow. Really? Seriously, James ... don't you think
they got it wrong too?

It seems the UNIX folk thought it was a mistake, as
they already had invested code and developer time in
the other direction.

Of all the places they cater to for the sake of "novice
developers?" What kind of place is serious C code for
a novice developer? You have to work your way up pretty
steadily in ability to be a serious C developer. And I
think the promotion of an unsigned type to a larger un-
signed type is only natural. I think promoting an un-
signed type to a signed type is crazy. It was surely
originally set to be unsigned for a reason.

I don't even see a good argument for C's logic, other
than that's the way some people were doing it. But I
think the far better solution would've been to tell
them, "Sorry, Charlie."

--
Rick C. Hodgin

Rick C. Hodgin

unread,
Sep 18, 2018, 3:09:47 PM9/18/18
to
On 9/18/2018 11:18 AM, Rick C. Hodgin wrote:
>     unsigned char a = 2;
>     unsigned char b = 2;
>     unsigned char c = 2;
>     uint32_t      d = 5;

Given that unsigned char translates to an 8-bit unsigned
integer, and uint32_t translates to a 32-bit unsigned int-
eger, what makes sense to me is this operation:

>         if (a + b + c > d)

Natural order of operation:

01: t1 = a + b
02: t2 = t1 + c
03: t3 = t2 > d

Order of operations with promotions injected (u8, u16,
u32 = 8-bit, 16-bit, 32-bit unsigned int):

// a, b, c all begin as u8

01: t1 = promote a to u16
02: t2 = promote b to u16
03: t3 = t1 + t2 as u16, tagged as a promoted result
04: t4 = promote c to u16
05: t5 = t3 + t4 as u16, tagged as a promoted result
06: t6 = promote t5 to u32
07: t7 = t6 > d as u32

Note: Many of these promotions are done in assembly at
the register level, but the operations still remain
there as logical step-by-step ops. Optimization
logic will factor in here and revise the ops for
its needs, such as promoting to u32 rather than u16
as that would be a natural machine word size, etc.

Is that not logical? What am I missing? Where would it
make more sense to promote a u8 to an s16 or s32 (signed
16-bit or signed 32-bit)?

--
Rick C. Hodgin

Anton Shepelev

unread,
Sep 18, 2018, 3:41:55 PM9/18/18
to
Rick C. Hodgin:

> I have this code (simplified for this example):
>
> #include <stdio.h>
> #include <stdint.h>
>
> unsigned char a = 2;
> unsigned char b = 2;
> unsigned char c = 2;
> uint32_t d = 5;
>
> int main(int argc, char* argv[])
> {
> if (a + b + c > d)
> printf("...0);
>
> return(0);
> }
>
> If I use godbolt.org and compare the MSVC x86 2015 and 2017
> versions with "/W4 /TC" (all warnings, compile as C code),
> then I get these messages. The same comes up without "/TC":
>
> https://godbolt.org
>
> MSVC:
> warning C4018: '>': signed/unsigned mismatch

Let me impersonate a C guru and quote the standard:

If an int can represent all values of the original type,
the value is converted to an int; otherwise, it is
converted to an unsigned int.

--
() ascii ribbon campaign -- against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]

Rick C. Hodgin

unread,
Sep 18, 2018, 3:46:00 PM9/18/18
to
On 9/18/2018 3:41 PM, Anton Shepelev wrote:
> Let me impersonate a C guru and quote the standard:
>
> If an int can represent all values of the original type,
> the value is converted to an int; otherwise, it is
> converted to an unsigned int.

What is the logic behind that? You've moved from unsigned to
signed for no reason other than it will fit in the positive
portion of the signed's range.

It was originally unsigned for a reason. Why migrate it to
signed without a cast?

I honestly consider this a fundamental flaw in C (and C++).

--
Rick C. Hodgin

Anton Shepelev

unread,
Sep 18, 2018, 3:54:23 PM9/18/18
to
Rick C. Hodgin to Anton Shepelev:

> > Let me impersonate a C guru and quote the standard:
> >
> > If an int can represent all values of the original
> > type, the value is converted to an int; otherwise, it
> > is converted to an unsigned int.
> >
> What is the logic behind that?

Would that I knew.

> You've moved from unsigned to signed for no reason other
> than it will fit in the positive portion of the signed's
> range.

Indeed.

> It was originally unsigned for a reason. Why migrate it
> to signed without a cast?

Because of the general approach of automatic promotions to
simplify and/or unify some things, which complicates and
confuses other things.

> I honestly consider this a fundamental flaw in C (and
> C++).

So do I.

David Brown

unread,
Sep 18, 2018, 4:24:00 PM9/18/18
to
I also think it would have been better to preserve signedness for
promotion (or even to forgo the concept of promotion altogether). But
there were good reasons for either choice, and the decision the
committee took is better than no decision. It's not hard to put in a
little cast on the few occasions it is needed.


Scott Lurndal

unread,
Sep 18, 2018, 4:37:08 PM9/18/18
to
"Rick C. Hodgin" <rick.c...@gmail.com> writes:
>On 9/18/2018 3:41 PM, Anton Shepelev wrote:
>> Let me impersonate a C guru and quote the standard:
>>
>> If an int can represent all values of the original type,
>> the value is converted to an int; otherwise, it is
>> converted to an unsigned int.
>
>What is the logic behind that? You've moved from unsigned to
>signed for no reason other than it will fit in the positive
>portion of the signed's range.

James posted the logic (extract from the standard) for you
to read, but while you replied to the article, you apparently
didn't read it, or you're just trolling again.

james...@alumni.caltech.edu

unread,
Sep 18, 2018, 5:14:17 PM9/18/18
to
On Tuesday, September 18, 2018 at 4:37:08 PM UTC-4, Scott Lurndal wrote:
> "Rick C. Hodgin" <rick.c...@gmail.com> writes:
> >On 9/18/2018 3:41 PM, Anton Shepelev wrote:
> >> Let me impersonate a C guru and quote the standard:
> >>
> >> If an int can represent all values of the original type,
> >> the value is converted to an int; otherwise, it is
> >> converted to an unsigned int.
> >
> >What is the logic behind that? You've moved from unsigned to
> >signed for no reason other than it will fit in the positive
> >portion of the signed's range.
>
> James posted the logic (extract from the standard) for you

Actually, I extracted it from the Rationale, not the standard.

The standard is primarily concerned with telling you "what"; the Rationale is intended to tell you "why" - but apparently Rich is still unclear what the reason is, after having read a description of the reason. I can understand disagreeing with the reason, but he shouldn't still be ignorant of what that reason was.

Rick C. Hodgin

unread,
Sep 18, 2018, 5:29:22 PM9/18/18
to
I'm not ignorant of what the reason is. I just can't believe that
was the decision they made. And I stated I disagree with it. I
was surprised by your reply to me, James. I think any person would
think the C committee got it wrong (especially in hindsight).

--
Rick C. Hodgin

Bart

unread,
Sep 18, 2018, 5:49:23 PM9/18/18
to
On 18/09/2018 18:03, james...@alumni.caltech.edu wrote:
> On Tuesday, September 18, 2018 at 12:05:12 PM UTC-4, Rick C. Hodgin wrote:

> Between the publication of K&R and the development of C89, a
> serious divergence had occurred among implementations in the
> evolution of integer promotion rules. Implementations fell into
> two major camps which may be characterized as unsigned preserving
> and value preserving. The difference between these approaches
> centered on the treatment of unsigned char and unsigned short
> when widened by the integer promotions, but the decision had an
> impact on the typing of constants as well (see §6.4.4.1).

> The unsigned preserving approach calls for promoting the two
> smaller unsigned types to unsigned int. This is a simple rule,
> and yields a type which is independent of execution environment.

Why wouldn't this also be value preserving? No sign change occurs, and
no narrowing.

> The unsigned preserving rules greatly increase the number of
> situations where unsigned int confronts signed int to yield a
> questionably signed result, whereas the value preserving rules
> minimize such confrontations. Thus, the value preserving rules
> were considered to be safer for the novice, or unwary,

What about the decision to use unsigned for mixed-sign arithmetic (eg.
signed * unsigned)?

It seems to me this would give rise to more questionable behaviour than
that other way. For example, the signed value only needs to be -1, a
very common value, for unexpected results to happen.

Using signed for mixed-sign arithmetic, things would only start to get
funny when the unsigned value was greater than 2147483647 (for 32 bits,
and even higher for 64 bits). Somewhat less common that tiny negative
numbers.

> programmer. After much discussion, the C89 Committee decided in
> favor of value preserving rules, despite the fact that the UNIX
> C compilers had evolved in the direction of unsigned preserving.

Since the affects can be subtle, and may not be seen at all if the
results are interpreted in certain ways, it is easy to forget about
these rules and to assume C works consistently.

And when you find it doesn't, there isn't anything wrong with objecting
to that and suggesting C might have got it wrong.

So unsigned 16+16 bits is signed, but unsigned 32+32 is unsigned. When
int is 32 bits, with probably different results on a different size of int.

These are not even of mixed sign. (See chart I posted in clc.)

--
bart

David Brown

unread,
Sep 19, 2018, 3:36:41 AM9/19/18
to
No matter what rules the C committee picked for integer promotion
(including having no promotion), and for mixed sign operations, there
would be expressions that gave the wrong answer or worked in a
counter-intuitive way. This is inevitable due to the limited size of
the types.

For example, if "u" and "v" are "unsigned short" and were promoted to
"unsigned int" rather than "int", then the expression "u + v - 10 >= 0"
would always be true - which is clearly nonsense mathematically.

The C committee were /not/ trying to figure out which rules would be
"right", or make most sense, or give the correct answer. They were
figuring out rules that would have the least chance of leading to errors
or surprising results. That's a different target.

Looking with modern eyes on the C promotion rules, I personally think
that signed preserving would have been better than promoting to "int".
But key to that is /modern/ eyes. When these rules were laid down,
there are three important points that the C committee had to consider
that do not apply when judging with modern eyes:

1. Existing C source code of the time should, as far as possible,
continue to work in the same way.

2. Existing C compilers of the time should continue to be usable where
possible (noting that some compilers promoted to "int", others preserved
signedness).

3. Existing C of the time was "int everywhere". Everything was "int" by
default - variables, expressions, function returns, function parameters.
Such "implicit int" is now gone from the language (or at least
obsolescent), but that was not the case when the integer promotion rules
were determined.



David Brown

unread,
Sep 19, 2018, 3:45:10 AM9/19/18
to
Clearly /not/ everyone thinks the C committee got it wrong. The
committee did not pick their rules by tossing a coin - they thought long
and hard about it before reaching a decision. And these were people
with long experience of C programming, C compiler writing, and
programming in general, and with an eye to the future of C. You can be
very sure they put a lot more thought and research into the matter than
either you or I have done. And they reached the conclusion they did,
based on the C world of the time. (See my reply to Bart for a few more
points - there is no need to repeat them here.)

With hindsight, in the modern C world, signedness preserving promotion
would be better for many people - I would prefer it myself. Actually, I
would prefer there to be /no/ promotion other than to a minimum common
type that spanned both value ranges. (Thus u8 + u8 would be done as u8,
but u16 + i8 would be done as i32.)

This does not mean that signedness preserving promotion would be better
for everyone - other people may, as the C committee did back then, give
more weighting to the argument that promoting to int reduces the risk of
having mixed sign operations.

When programming in C - as always - you need to know the rules of C,
even when you think they are sub-optimal. It is not hard to get the
effects you want in this case. You just use casts, or temporary
variables of the types you want, in order to get the results. And you
can often use compiler warnings to help catch cases where you got it wrong.


Bart

unread,
Sep 19, 2018, 5:57:40 AM9/19/18
to
On 19/09/2018 08:36, David Brown wrote:
> On 18/09/18 23:49, Bart wrote:

>> These are not even of mixed sign. (See chart I posted in clc.)
>>
>
> No matter what rules the C committee picked for integer promotion
> (including having no promotion), and for mixed sign operations, there
> would be expressions that gave the wrong answer or worked in a
> counter-intuitive way. This is inevitable due to the limited size of
> the types.

By using signed for mixed arithmetic instead of unsigned (more of a beef
for me than sign change on promotion, which is a new quirk I wasn't
really aware of), then the cases where it goes wrong will be pushed out
to the extreme ranges of possible values (well, half-way to those
extremes, instead of clustered around zero).


> For example, if "u" and "v" are "unsigned short" and were promoted to
> "unsigned int" rather than "int", then the expression "u + v - 10 >= 0"
> would always be true - which is clearly nonsense mathematically.

It already creates nonsense:

uint64_t u=3,v=4;

printf("u = %llu, v = %llu\n",u,v);
printf("signed(u+v-10) = %lld\n",u+v-10);
printf("unsigned(u+v-10) = %llu\n",u+v-10);

if (u+v-10 >= 0) puts("u+v-10 >= 0"); else puts("u+v-10 < 0");

This tells me that u+v-10 (which has a mathematical value of -3) is
greater than zero. Due to using unsigned for the "-" operation. If I
force that to be signed:

if ((int64_t)(u+v)-10 >= 0) puts("u+v-10 >= 0");
else puts("u+v-10 < 0");

Then I get the mathematically correct answer. It will only start to go
wrong when u+v is greater than about 2**63.

Of course, if you do: 'v = u-10;' when u<10, then you will always end
up with a very large unsigned value. There will always be such problems,
but C as it is makes it worse I think.

--
bart

Bart

unread,
Sep 19, 2018, 6:11:27 AM9/19/18
to
On 19/09/2018 08:44, David Brown wrote:

> With hindsight, in the modern C world, signedness preserving promotion
> would be better for many people - I would prefer it myself. Actually, I
> would prefer there to be /no/ promotion other than to a minimum common
> type that spanned both value ranges. (Thus u8 + u8 would be done as u8,
> but u16 + i8 would be done as i32.)

That's biased towards mixed-sign operations:

u8+u8 => u8 means 255+1 => 0

u16+i8 => i32 means 65535+1 => 65536

Perhaps u8+u8 should be done as u16.

--
bart

bol...@cylonhq.com

unread,
Sep 19, 2018, 6:12:12 AM9/19/18
to
On Wed, 19 Sep 2018 10:57:26 +0100
Bart <b...@freeuk.com> wrote:
>greater than zero. Due to using unsigned for the "-" operation. If I
>force that to be signed:
>
> if ((int64_t)(u+v)-10 >= 0) puts("u+v-10 >= 0");
> else puts("u+v-10 < 0");
>
>Then I get the mathematically correct answer. It will only start to go
>wrong when u+v is greater than about 2**63.
>
>Of course, if you do: 'v = u-10;' when u<10, then you will always end
>up with a very large unsigned value. There will always be such problems,
>but C as it is makes it worse I think.

You shouldn't really be doing mathematical operations with unsigned anything
in the first place. They're really meant for counters and bit/byte operations.

Still, look on the bright side, at least C and C++ have unsigned. Thats more
than Java got, which considering it was originally meant as an embedded
language seems an absurd decision to me.


David Brown

unread,
Sep 19, 2018, 6:19:03 AM9/19/18
to
The point is, as you say, there will always be such problems. You can't
get away from that. The C rules are based on the idea that most numbers
fit fine within the range of int, so moving anything smaller into int
will most likely give you the right answer. It won't always be the way
you want it, and might not be the rule you think is best, but it works
fine for much of the time. No other choice of rule would be any
different - it's just the details of what it gets right and wrong that
would differ.


David Brown

unread,
Sep 19, 2018, 6:38:01 AM9/19/18
to
On 19/09/18 12:11, Bart wrote:
> On 19/09/2018 08:44, David Brown wrote:
>
>> With hindsight, in the modern C world, signedness preserving promotion
>> would be better for many people - I would prefer it myself. Actually, I
>> would prefer there to be /no/ promotion other than to a minimum common
>> type that spanned both value ranges. (Thus u8 + u8 would be done as u8,
>> but u16 + i8 would be done as i32.)
>
> That's biased towards mixed-sign operations:
>
> u8+u8 => u8 means 255+1 => 0

That is what I would want, yes. Actually, sometimes I would want
unsigned types with undefined behaviour for overflow, like their signed
versions (and conversely, I sometimes want signed types with wrapping
overflow. And sometimes I want saturation for both signed and unsigned
types. And sometimes I want types to grow to cover the full range of
possible values. I want a choice of everything!).

More to the point, if I am using 8 bit types for arithmetic, I want
8-bit arithmetic.

>
> u16+i8 => i32 means 65535+1 => 65536
>
> Perhaps u8+u8 should be done as u16.
>

No, not for me.

The point of the example above is that i32 is the smallest type that can
hold all values of u16, and also all values of i8.

If you think u8 + u8 should be done as u16, then you should also expect
u32 + u32 to be done as u64, and u64 + u64 to be done as u128.

Bart

unread,
Sep 19, 2018, 7:05:37 AM9/19/18
to
On 19/09/2018 11:37, David Brown wrote:
> On 19/09/18 12:11, Bart wrote:

>> That's biased towards mixed-sign operations:
>>
>> u8+u8 => u8 means 255+1 => 0
>
> That is what I would want, yes. Actually, sometimes I would want
> unsigned types with undefined behaviour for overflow, like their signed
> versions (and conversely, I sometimes want signed types with wrapping
> overflow. And sometimes I want saturation for both signed and unsigned
> types. And sometimes I want types to grow to cover the full range of
> possible values. I want a choice of everything!).
>
> More to the point, if I am using 8 bit types for arithmetic, I want
> 8-bit arithmetic.

What would you have for u8+i8?

(I've looked at a compiler where I've recently got rid of C-style
promotions to 'int', which introduced all sorts of complications.

There, with mixed integer operands (of size and type), I only widen one
to be the same width as the other, with signed always dominant. So
u16+i8 is done as i16. Not i32. And u8+i8 would be i8.

There are already so many issues working with such mixed int types, that
65535+1 giving zero here is a minor one. It is just necessary to take
care working with narrow types.)

>>
>> u16+i8 => i32 means 65535+1 => 65536
>>
>> Perhaps u8+u8 should be done as u16.
>>
>
> No, not for me.
>
> The point of the example above is that i32 is the smallest type that can
> hold all values of u16, and also all values of i8.
>
> If you think u8 + u8 should be done as u16, then you should also expect
> u32 + u32 to be done as u64, and u64 + u64 to be done as u128.

And you would have a similar problem with u64 + i32; you'd need i128.

--
bart

David Brown

unread,
Sep 19, 2018, 7:13:24 AM9/19/18
to
On 19/09/18 13:05, Bart wrote:
> On 19/09/2018 11:37, David Brown wrote:
>> On 19/09/18 12:11, Bart wrote:
>
>>> That's biased towards mixed-sign operations:
>>>
>>> u8+u8 => u8 means 255+1 => 0
>>
>> That is what I would want, yes. Actually, sometimes I would want
>> unsigned types with undefined behaviour for overflow, like their signed
>> versions (and conversely, I sometimes want signed types with wrapping
>> overflow. And sometimes I want saturation for both signed and unsigned
>> types. And sometimes I want types to grow to cover the full range of
>> possible values. I want a choice of everything!).
>>
>> More to the point, if I am using 8 bit types for arithmetic, I want
>> 8-bit arithmetic.
>
> What would you have for u8+i8?
>

The smallest type that can hold both these ranges - i16.

> (I've looked at a compiler where I've recently got rid of C-style
> promotions to 'int', which introduced all sorts of complications.
>
> There, with mixed integer operands (of size and type), I only widen one
> to be the same width as the other, with signed always dominant. So
> u16+i8 is done as i16. Not i32. And u8+i8 would be i8.
>
> There are already so many issues working with such mixed int types, that
> 65535+1 giving zero here is a minor one. It is just necessary to take
> care working with narrow types.)

However it is done, there will /always/ be some complications. And
there will always will be times when it is most convenient to have
promotions, and times when it is most convenient not to have promotions,
and unless you widen types enough, there will always be the risk of
overflow.

While I might have picked different rules myself for a language, I would
not want to change C's rules. That would just be confusing and break
existing code, no matter how they were changed. A single set of rules
may be imperfect, but it is better than multiple sets of rules!


>
>>>
>>> u16+i8 => i32 means 65535+1 => 65536
>>>
>>> Perhaps u8+u8 should be done as u16.
>>>
>>
>> No, not for me.
>>
>> The point of the example above is that i32 is the smallest type that can
>> hold all values of u16, and also all values of i8.
>>
>> If you think u8 + u8 should be done as u16, then you should also expect
>> u32 + u32 to be done as u64, and u64 + u64 to be done as u128.
>
> And you would have a similar problem with u64 + i32; you'd need i128.
>

Yes.


David Brown

unread,
Sep 19, 2018, 7:14:20 AM9/19/18
to
At some point, of course, you'd be getting compiler warnings or an error
saying the type sizes are getting ridiculous :-)

Rick C. Hodgin

unread,
Sep 19, 2018, 7:16:08 AM9/19/18
to
On Wednesday, September 19, 2018 at 3:36:41 AM UTC-4, David Brown wrote:
> For example, if "u" and "v" are "unsigned short" and were promoted to
> "unsigned int" rather than "int", then the expression "u + v - 10 >= 0"
> would always be true - which is clearly nonsense mathematically.

The problem there is in using unsigned arithmetic for a calculation
that may become negative. It's a programmer error, not a C error.

It's not the compiler's job to hold the developer's hand, but only
to provide them with the resources they need to thrive.

--
Rick C. Hodgin

Rick C. Hodgin

unread,
Sep 19, 2018, 7:27:17 AM9/19/18
to
That is the approach CAlive takes, and storage operations are saturated
into their max value:

u8 a, b, c;

a = 255;
b = 100;
c = a + b;
// c is now 255 in CAlive

Operations:

01: t1 = promote a to u16
02: t2 = promote b to u16
03: t3 = t1 + t2, tagged as promoted u16 result
04: t4 = sign_saturate_u16_to_u8(t3);
05: c = t4 // c is set to 255, max value

CAlive will keep the value as u16 in case of additional operators:

a = 200;
b = 219;
if (a + b > 418)
printf("For triple time I'd eat Beanie." );

Operations:

01: t1 = promote a to u16
02: t2 = promote b to u16
03: t3 = t1 + t2, tagged as promoted u16 result
04: t4 = t3 > 418. // t4 is 1

It's as it should be for a language.

--
Rick C. Hodgin

Rick C. Hodgin

unread,
Sep 19, 2018, 7:31:37 AM9/19/18
to
On Wednesday, September 19, 2018 at 7:05:37 AM UTC-4, Bart wrote:
> What would you have for u8+i8?

I call them u8 for unsigned, and s8 for signed. It would be s16.

> And you would have a similar problem with u64 + i32; you'd need i128.

CAlive uses type bi (big integer, arbitrary precision) for values above
u64 and s64. The smallest bi is 128-bit. And bfp for big floating
point, the smallest bfp is 128-bit as well.

--
Rick C. Hodgin

David Brown

unread,
Sep 19, 2018, 7:44:08 AM9/19/18
to
On 19/09/18 13:27, Rick C. Hodgin wrote:
> On Wednesday, September 19, 2018 at 6:11:27 AM UTC-4, Bart wrote:
>> On 19/09/2018 08:44, David Brown wrote:
>>
>>> With hindsight, in the modern C world, signedness preserving promotion
>>> would be better for many people - I would prefer it myself. Actually, I
>>> would prefer there to be /no/ promotion other than to a minimum common
>>> type that spanned both value ranges. (Thus u8 + u8 would be done as u8,
>>> but u16 + i8 would be done as i32.)
>>
>> That's biased towards mixed-sign operations:
>>
>> u8+u8 => u8 means 255+1 => 0
>> u16+i8 => i32 means 65535+1 => 65536
>>
>> Perhaps u8+u8 should be done as u16.
>
> That is the approach CAlive takes, and storage operations are saturated
> into their max value:
>
> u8 a, b, c;
>
> a = 255;
> b = 100;
> c = a + b;
> // c is now 255 in CAlive
>

Saturation is a /very/ different way of handling overflows. Sometimes
it is a useful way to do it, but you have to be aware of the costs here.
If you have saturation, you no longer have associative arithmetic - "x
+ 1 - 1" is no longer the same as "x". It might be the same in some
circumstances, but different in others, depending on the way the
expression is split up with temporaries - that is not good. It also
involves quite significant run-time costs on most platforms, and gives
results that would be surprising to many programmers.

I am fully in favour of saturation as an option, but I would avoid it as
default - I'd have it as a type qualifier or something like that.

> Operations:
>
> 01: t1 = promote a to u16
> 02: t2 = promote b to u16
> 03: t3 = t1 + t2, tagged as promoted u16 result
> 04: t4 = sign_saturate_u16_to_u8(t3);
> 05: c = t4 // c is set to 255, max value
>
> CAlive will keep the value as u16 in case of additional operators:
>
> a = 200;
> b = 219;
> if (a + b > 418)
> printf("For triple time I'd eat Beanie." );
>
> Operations:
>
> 01: t1 = promote a to u16
> 02: t2 = promote b to u16
> 03: t3 = t1 + t2, tagged as promoted u16 result
> 04: t4 = t3 > 418. // t4 is 1
>
> It's as it should be for a language.
>

Don't be so categorical. Consider the various possibilities (undefined
behaviour, wrapping, saturation, throwing an error, increasing the size
of the types, "NaN" values), and their pros and cons. Look at how other
languages handle the situation. Look at C (making sure you have the
correct C rules), Ada, Java, Pascal. Then try to think what would be
best for your language - whether it be one option, or whether you have
type qualifiers or different types with different behaviours. (Avoid
compiler switch options.)

What you can be sure of is that if you have one way of handling this
sort of thing, it will be wrong for some code and counter-intuitive to
some developers. There is /no/ right answer here - not with finite
limits on your type sizes. There is no "as it should be for a
language". There is just a matter of picking the rules that give the
smallest risk of problems for developers in the language.


David Brown

unread,
Sep 19, 2018, 7:49:13 AM9/19/18
to
On 19/09/18 13:15, Rick C. Hodgin wrote:
> On Wednesday, September 19, 2018 at 3:36:41 AM UTC-4, David Brown wrote:
>> For example, if "u" and "v" are "unsigned short" and were promoted to
>> "unsigned int" rather than "int", then the expression "u + v - 10 >= 0"
>> would always be true - which is clearly nonsense mathematically.
>
> The problem there is in using unsigned arithmetic for a calculation
> that may become negative. It's a programmer error, not a C error.

I agree that it is a programmer error, not a C error (or sort-of-C
error, since this was with non-standard C promotion rules). C has its
rules for promotions - they cannot be in error, as they are the defining
rules. So any code the programmer writes that does not do what he/she
wants is a programmer error.

The issue is what choice of rules for a language would minimise the risk
of the programmer making an error. The C committee picked a set that
they felt minimised the risk (given the type of C used at the time). My
point is that picking different rules - such as using
signedness-preserving promotion - would have changed which expressions
would be correct or incorrect, but it would /not/ have eliminated errors
due to promotions.

Rick C. Hodgin

unread,
Sep 19, 2018, 7:55:20 AM9/19/18
to
On 9/19/2018 7:43 AM, David Brown wrote:
> On 19/09/18 13:27, Rick C. Hodgin wrote:
>> On Wednesday, September 19, 2018 at 6:11:27 AM UTC-4, Bart wrote:
>>> On 19/09/2018 08:44, David Brown wrote:
>>>
>>>> With hindsight, in the modern C world, signedness preserving promotion
>>>> would be better for many people - I would prefer it myself. Actually, I
>>>> would prefer there to be /no/ promotion other than to a minimum common
>>>> type that spanned both value ranges. (Thus u8 + u8 would be done as u8,
>>>> but u16 + i8 would be done as i32.)
>>>
>>> That's biased towards mixed-sign operations:
>>>
>>> u8+u8 => u8 means 255+1 => 0
>>> u16+i8 => i32 means 65535+1 => 65536
>>>
>>> Perhaps u8+u8 should be done as u16.
>>
>> That is the approach CAlive takes, and storage operations are saturated
>> into their max value:
>>
>> u8 a, b, c;
>>
>> a = 255;
>> b = 100;
>> c = a + b;
>> // c is now 255 in CAlive
>>
>
> Saturation is a /very/ different way of handling overflows. Sometimes
> it is a useful way to do it, but you have to be aware of the costs here.
> If you have saturation, you no longer have associative arithmetic - "x
> + 1 - 1" is no longer the same as "x".

In CAlive, saturation only happens on hard assignment. Promotion
is used throughout calculations.

>> Operations:
>>
>> 01: t1 = promote a to u16
>> 02: t2 = promote b to u16
>> 03: t3 = t1 + t2, tagged as promoted u16 result
>> 04: t4 = sign_saturate_u16_to_u8(t3);
>> 05: c = t4 // c is set to 255, max value
>>
>> CAlive will keep the value as u16 in case of additional operators:
>>
>> a = 200;
>> b = 219;
>> if (a + b > 418)
>> printf("For triple time I'd eat Beanie." );
>>
>> Operations:
>>
>> 01: t1 = promote a to u16
>> 02: t2 = promote b to u16
>> 03: t3 = t1 + t2, tagged as promoted u16 result
>> 04: t4 = t3 > 418. // t4 is 1
>>
>> It's as it should be for a language.
>
> Don't be so categorical. Consider the various possibilities (undefined
> behaviour, wrapping, saturation, throwing an error, increasing the size
> of the types, "NaN" values), and their pros and cons.

CAlive provides <|decision|> casks for this purpose. Each
possible "thrown" condition can be captured on each line
using those casks:

a = 200;
b = 219;
if (a + b <|overflow|my_overflow_func()||> > 418)
printf("Yessiree buddy!");

In this case, the logic would be like this:

a = 200;
b = 219;
u16 t1 = a + b;
if (t1 > 255)
my_overflow_func();
if (t1 > 418)
printf("Yessiree buddy!");

Each cask is it's own self-contained thing, and it can be
injected anywhere in source code, and uses information
relative to where it is for its assignment, and you can
look at the code it generates to see if you put it in
the correct place. The general syntax is:

<|type|code||>

type = overflow, underflow, nan, etc.

> (Avoid compiler switch options.)

In my opinion, and I've heard this from several people here
in the C groups ... avoiding compiler switch options is an
absolutely ridiculous idea. I'm amazed people make such
claims. It honestly makes me think you're trying to hobble
my design, along with some of the other advice you give.
And yes I am serious.

There have to be ways to turn things on or off. They can
be added as something like a #pragma in source code, but to
limit the ability to add compiler command-line switches,
which allow external tools to use their various settings
however they do to then be translated and conveyed through
a standard protocol ... it's absolutely wrong advice. I'm
amazed any intelligent developer would suggest it, unless
they were on an agenda to give out wrong advice as per that
agenda.

--
Rick C. Hodgin

Rick C. Hodgin

unread,
Sep 19, 2018, 8:35:08 AM9/19/18
to
On 9/19/2018 7:55 AM, Rick C. Hodgin wrote:
> CAlive provides <|decision|> casks for this purpose.  Each
> possible "thrown" condition can be captured on each line
> using those casks:
>
>     a = 200;
>     b = 219;
>     if (a + b <|overflow|my_overflow_func()||> > 418)
>         printf("Yessiree buddy!");
>
> In this case, the logic would be like this:
>
>     a = 200;
>     b = 219;
>     u16 t1 = a + b;
>     if (t1 > 255)
>         my_overflow_func();
>     if (t1 > 418)
>         printf("Yessiree buddy!");

I should add, you can override the value in use using a
placeholder variable:

a = 200;
b = 219;
==> // Uses "x" as a placeholder variable
==> if (a + b <||x|overflow|my_overflow_func(x)||> > 418)
printf("Yessiree buddy!");

In this case, the logic would be like this:

a = 200;
b = 219;
u16 t1 = a + b;
if (t1 > 255)
==> t1 = my_overflow_func(t1);
if (t1 > 418)
printf("Yessiree buddy!");

--
Rick C. Hodgin

David Brown

unread,
Sep 19, 2018, 8:36:17 AM9/19/18
to
I don't quite know what you mean by "hard assignment". In most C
compilers, code like this would not involve any storage to memory, but
it would involve turning the results of "a + b" into a u8 type (i.e., a
value 99 in C).
To be brutally honest, I /much/ prefer a syntax like this second one to
your casks. It is not at all clear to me if the overflow function is
called as well as the passing the "if" test (which might be reasonable
for an overflow, but not for an underflow or if the comparison had been
< 418). With the expanded "C" version, it is clear.


> Each cask is it's own self-contained thing, and it can be
> injected anywhere in source code, and uses information
> relative to where it is for its assignment, and you can
> look at the code it generates to see if you put it in
> the correct place. The general syntax is:
>
> <|type|code||>
>
> type = overflow, underflow, nan, etc.
>

I honestly can't help feeling this is going to be ugly and unclear. I
would want either explicit handling (like your expanded C version
above), or possibly an implicit error handling system (like exceptions
in many languages). Your casks always seem to me to be the wrong place
to put things. I may not be your target audience for your language, but
casks would certainly be a turn-off for me. It's up to you to decide if
you think my opinion would be common amongst other potential users of
your language, or if they would agree with you about the usefulness of
casks. Your language has some new ideas that I like, but this is not
one of them.

>> (Avoid compiler switch options.)
>
> In my opinion, and I've heard this from several people here
> in the C groups ... avoiding compiler switch options is an
> absolutely ridiculous idea. I'm amazed people make such
> claims. It honestly makes me think you're trying to hobble
> my design, along with some of the other advice you give.
> And yes I am serious.
>

No, not at all - you are entirely mistaken.

Consider a "brightness" function for pixel colours. If you have
saturation on u8 arithmetic, you could write it as :

u8 brightness(u8 red, u8 green, u8 blue) {
return red + green + blue;
}

If you had two's complement wrapping on overflow, it would be completely
wrong. Agreed so far?


One possible way to allow programmers to choose overflow behaviour,
between saturation and wrapping, would be to have a command-line switch.
This may sound like a fine idea, letting programmers choose the default
behaviour they want.

But then the same source code does something entirely different
depending on the command-line switch. If you copy-and-paste the same
function source code into a different file, it might result in different
behaviour, depending on the switches used for that compilation. If you
look at the code in isolation, you can't tell if it is right or wrong,
or know that it relies on a particular choice of overflow behaviour.

This is /bad/.


On the other hand, if the function is written:

sat u8 brightness(sat u8 red, sat u8 green, sat u8 blue) {
return red + green + blue;
}

or :

u8 brightness(u8 red, u8 green, u8 blue) {
return sat_add(red, green, blue);
}

or :

u8 brightness(u8 red, u8 green, u8 blue) {
return red +.sat green +.sat blue;
}

Then the code is clear, and it stands by itself. (I have no opinions as
to which syntax is best - you pick.)


Do you see what I am getting at here?


Things like optimisation or warning choices are fine for command-line
switches - they affect the quality and efficiency of the generated code,
but not its correctness.

(In the interests of fairness and completeness, I should note that I
don't like gcc's code generation options like "-fwrapv" or
"-fno-strict-aliasing". When I need to work with external code that
requires these options, I put them in as pragmas in the code rather than
command-line options, to keep correctness independent from compiler
switches.)


> There have to be ways to turn things on or off. They can
> be added as something like a #pragma in source code, but to
> limit the ability to add compiler command-line switches,
> which allow external tools to use their various settings
> however they do to then be translated and conveyed through
> a standard protocol ... it's absolutely wrong advice. I'm
> amazed any intelligent developer would suggest it, unless
> they were on an agenda to give out wrong advice as per that
> agenda.
>

You know fine that I do not have an agenda of giving out wrong advice.
Regardless of any arguments or disagreements we might have about
non-technical subjects, or on technical aspects of your language, or on
its practicality, you /know/ that I give my opinions honestly and with
the best technical knowledge and experience I can.


Bart

unread,
Sep 19, 2018, 8:59:15 AM9/19/18
to
On 19/09/2018 13:36, David Brown wrote:
> On 19/09/18 13:55, Rick C. Hodgin wrote:

>> In CAlive, saturation only happens on hard assignment. Promotion
>> is used throughout calculations.
>
> I don't quite know what you mean by "hard assignment".


I think he means calculations are done with wider types as necessary,
but when stored to memory via assignment, then saturation is applied if
the destination is narrower.

(To me that would be such a rare requirement, and so unexpected in other
cases, that I would use an explicit function call to do that conversion.)

> No, not at all - you are entirely mistaken.
>
> Consider a "brightness" function for pixel colours. If you have
> saturation on u8 arithmetic, you could write it as :
>
> u8 brightness(u8 red, u8 green, u8 blue) {
> return red + green + blue;
> }
>
> If you had two's complement wrapping on overflow, it would be completely
> wrong. Agreed so far?

Both signed and unsigned would usually give the wrong results.

(Actually the example is flawed. A 'luminance' function would return the
weighted sum of R, G, B, which is 255 max. While adding brightness to a
pixel involves add a value to each component, which is where you might
want saturation to occur.

But let's say to want u8+u8+u8 to return a u8 saturated value.)

> But then the same source code does something entirely different
> depending on the command-line switch. If you copy-and-paste the same
> function source code into a different file, it might result in different
> behaviour, depending on the switches used for that compilation. If you
> look at the code in isolation, you can't tell if it is right or wrong,
> or know that it relies on a particular choice of overflow behaviour.
>
> This is /bad/.

This is the thrust of half my complaints against C.

> u8 brightness(u8 red, u8 green, u8 blue) {
> return sat_add(red, green, blue);
> }
>
> or :
>
> u8 brightness(u8 red, u8 green, u8 blue) {
> return red +.sat green +.sat blue;
> }
>
> Then the code is clear, and it stands by itself. (I have no opinions as
> to which syntax is best - you pick.)

No need to invent operators for something that is so rarely needed; a
function would do.

But surely you don't need one to do the additions for you: just do
regular addition, using wide enough values to store the results, then
use a sat function to clamp the result.

And actually this example, if the additions are done as i32 or u32, can
simply become:

return min(red+green+blue, 255)

--
bart

Rick C. Hodgin

unread,
Sep 19, 2018, 9:00:44 AM9/19/18
to
"c = a + b;" is a hard assignemnt of the promoted result of "a + b"
to a variable. "if (a + b > 418)" uses the same promoted result as
part of the expression, but does not store it anywhere. As such,
in these examples, c would be 255, and the value used to compare
against 418 would be the sum of a + b as it is, promoted to u16 if
they were u8 to begin with.

>> CAlive provides <|decision|> casks for this purpose. Each
>> possible "thrown" condition can be captured on each line
>> using those casks:
>>
>> a = 200;
>> b = 219;
>> if (a + b <|overflow|my_overflow_func()||> > 418)
>> printf("Yessiree buddy!");
>>
>> In this case, the logic would be like this:
>>
>> a = 200;
>> b = 219;
>> u16 t1 = a + b;
>> if (t1 > 255)
>> my_overflow_func();
>> if (t1 > 418)
>> printf("Yessiree buddy!");
>>
>
> To be brutally honest, I /much/ prefer a syntax like this second one to
> your casks ... With the expanded "C" version, it is clear.

Code it that way. CAlive allows you to code it the first way
and auto-injects that code for you. Plus, in the GUI editor
the first line shows up like this:

if (a + b <|> > 418)

And the <|> is in a yellow background with black text, which
contrasts to the foreground color of the editor. It's also
shown in a reduced font size so it looks closer to small
diamond there.

All casks have the ability to be expanded or collapsed by a
GUI editor setting, or individually.

>> Each cask is it's own self-contained thing, and it can be
>> injected anywhere in source code, and uses information
>> relative to where it is for its assignment, and you can
>> look at the code it generates to see if you put it in
>> the correct place. The general syntax is:
>>
>> <|type|code||>
>>
>> type = overflow, underflow, nan, etc.
>
> I honestly can't help feeling this is going to be ugly and unclear.

Don't use them. CAlive will still allow code as C does, and
you can code that way to your heart's delight.

>>> (Avoid compiler switch options.)
>>
>> In my opinion, and I've heard this from several people here
>> in the C groups ... avoiding compiler switch options is an
>> absolutely ridiculous idea. I'm amazed people make such
>> claims. It honestly makes me think you're trying to hobble
>> my design, along with some of the other advice you give.
>> And yes I am serious.
>
> No, not at all - you are entirely mistaken.
>
> Consider a "brightness" function for pixel colours. If you have
> saturation on u8 arithmetic, you could write it as :
>
> u8 brightness(u8 red, u8 green, u8 blue) {
> return red + green + blue;
> }
>
> If you had two's complement wrapping on overflow, it would be completely
> wrong. Agreed so far?

I would say the algorithm is wrong already. The colors r,g,b
account for 35%, 54% and 11% relative intensity of light, so
you cannot perform the logic you have above appropriately.

It would need to be:

u8 brightness(u8 r, u8 g, u8 b) {
return((u8)((f32)r*0.34f + (f32)g*0.54f + (f32)b*0.11f));

In the case of the proper algorithm, there's no issue. :-)

> One possible way to allow programmers to choose overflow behaviour,
> between saturation and wrapping, would be to have a command-line switch.
> This may sound like a fine idea, letting programmers choose the default
> behaviour they want.

I allow this feature by enclosing the block that is to operate
as C does in a _c {..} block, a _c {{..}} block, or a _c {{..
}(_c)} non-aligning-block.

It can be messy in source code, but in the GUI editor it makes
it more tolerable and visual.

u8 brightness(u8 red, u8 green, u8 blue) {
_c {
return red + green + blue;
}
}

In this case, no auto-promotion, and things will wrap as they
do in C. Other examples:

u8 brightness(u8 red, u8 green, u8 blue) {
_c {{
return red + green + blue;
}}
}

u8 brightness(u8 red, u8 green, u8 blue) {
_c {{ return red + green + blue; }(_c)}
}

The purpose of the {{..}(x)} blocks are to allow mis-aligned
blocks. Here's a contrived example showing C code and CAlive
code blocks overlapping:

func example
| params u8 red, u8 grn, u8 blu
| returns u8 color
{
_c {{
color = red + grn + blu;
printf("Overflow value = %d, ", red);
_ca {{ // CAlive block
adhoc get_value { return(red + grn + blu); }
}(_c)}
printf("saturated = %d\n", get_value);
}}

In the GUI editor, the code would appear like this:

func example
| params u8 red, u8 grn, u8 blu
| returns u8 color
{
_c +--------------------------------------+
|color = red + grn + blu; |
|printf("Overflow value = %d, ", red); |
_ca+--------------------------------------|------+
|adhoc get_value { return(red + grn + blu); } |
+--------------------------------------+ |
| printf("saturated = %d\n", get_value); |
+---------------------------------------------+

There are different colored boxes which encapsulate the code.
And within the boxes, certain features are allowed or dis-
allowed based on many factors.

> But then the same source code does something entirely different
> depending on the command-line switch. If you copy-and-paste the same
> function source code into a different file, it might result in different
> behaviour, depending on the switches used for that compilation. If you
> look at the code in isolation, you can't tell if it is right or wrong,
> or know that it relies on a particular choice of overflow behaviour.
>
> This is /bad/.

Each source file is compiled using whatever options it should.
CAlive allows a settings input file for options, so they don't
have to be specified individually on a command line, but a single
file with options is provided.

> On the other hand, if the function is written:
>
> sat u8 brightness(sat u8 red, sat u8 green, sat u8 blue) {
> return red + green + blue;
> }
>
> or :
>
> u8 brightness(u8 red, u8 green, u8 blue) {
> return sat_add(red, green, blue);
> }
>
> or :
>
> u8 brightness(u8 red, u8 green, u8 blue) {
> return red +.sat green +.sat blue;
> }
>
> Then the code is clear, and it stands by itself. (I have no opinions as
> to which syntax is best - you pick.)

I have ways to do this already.

> Do you see what I am getting at here?
>
>
> Things like optimisation or warning choices are fine for command-line
> switches - they affect the quality and efficiency of the generated code,
> but not its correctness.

Of course. And it's as it should be in my opinion.

>> There have to be ways to turn things on or off. They can
>> be added as something like a #pragma in source code, but to
>> limit the ability to add compiler command-line switches,
>> which allow external tools to use their various settings
>> however they do to then be translated and conveyed through
>> a standard protocol ... it's absolutely wrong advice. I'm
>> amazed any intelligent developer would suggest it, unless
>> they were on an agenda to give out wrong advice as per that
>> agenda.
>>
>
> You know fine that I do not have an agenda of giving out wrong advice.

I do not know this. You often give out bad advice. I think
you honestly believe you are giving out your best advice, but
I know you are also deceived by the enemy of God into believing
wrong things, so the things you think are right are wrong, and
the reasons why you believe what you do are not your own, but
you have bought into them because you acquiesce to sin's call
by the evil spirits' leading and prompting you.

You've let them in over decades, David, and now they're there
in your mind affecting all of your thoughts, beliefs, actions,
etc.

Until you are willing to turn toward Christ, acknowledge your
sin, acknowledge your helpless state over their power because
of the ravages of sin against your very nature in sin, then you
have no hope. You will go through life believing you are right
when you are wrong, believing you are doing everything correctly
when you are being deceived into incorrect things, etc.

Jesus takes all of that away, and His Holy Spirit does guide you
rightly from within. It's why I point you to Him.

> Regardless of any arguments or disagreements we might have about
> non-technical subjects, or on technical aspects of your language, or on
> its practicality, you /know/ that I give my opinions honestly and with
> the best technical knowledge and experience I can.

I know that you believe you do this. I can only teach you that
you are wrong. I can't make you believe it. You have to have
that inner spark driving you to move, and that only comes from
God, and that only comes to those who are being saved (John 6:44).

--
Rick C. Hodgin

Rick C. Hodgin

unread,
Sep 19, 2018, 9:04:13 AM9/19/18
to
On 9/19/2018 8:59 AM, Bart wrote:
> On 19/09/2018 13:36, David Brown wrote:
>> On 19/09/18 13:55, Rick C. Hodgin wrote:
>>> In CAlive, saturation only happens on hard assignment.  Promotion
>>> is used throughout calculations.
>>
>> I don't quite know what you mean by "hard assignment".
>
> I think he means calculations are done with wider types as necessary, but
> when stored to memory via assignment, then saturation is applied if the
> destination is narrower.

Correct.

> (To me that would be such a rare requirement, and so unexpected in other
> cases, that I would use an explicit function call to do that conversion.)

CAlive uses promotion on nearly every calculation. It sign-
saturates nearly every result. It does this so the intermediate
calculations can exceed their bit sizes, and still compute their
values correctly should the final result be in range.

CAlive looks at data from the point of view of the calculation
and not the limitation of the type representation.

You can override the ability to require a promotion by specifying
range information on variables. If a value can only be 0..100,
and another can only be 0..100, then two u8's being added together
would never exceed 255, so no need for promotion.

--
Rick C. Hodgin

David Brown

unread,
Sep 19, 2018, 9:21:58 AM9/19/18
to
On 19/09/18 15:00, Rick C. Hodgin wrote:
> On 9/19/2018 8:36 AM, David Brown wrote:
>> On 19/09/18 13:55, Rick C. Hodgin wrote:

>> To be brutally honest, I /much/ prefer a syntax like this second one to
>> your casks ... With the expanded "C" version, it is clear.
>
> Code it that way. CAlive allows you to code it the first way
> and auto-injects that code for you.

In programming, you spend a fraction of your time writing - and a lot
more time reading. It does not help me if /I/ choose not to use casks,
if other people write code that is full of them. (And if other people
don't use them noticeably, then why would they be in the language at all?)

Choices are often a good thing, but not always. And here I could choose
to avoid /writing/ casks, but I could not choose to avoid having to read
them and understand them.

(But enough about casks - you know my opinion, I know yours.)


>
>>>> (Avoid compiler switch options.)
>>>
>>> In my opinion, and I've heard this from several people here
>>> in the C groups ... avoiding compiler switch options is an
>>> absolutely ridiculous idea. I'm amazed people make such
>>> claims. It honestly makes me think you're trying to hobble
>>> my design, along with some of the other advice you give.
>>> And yes I am serious.
>>
>> No, not at all - you are entirely mistaken.
>>
>> Consider a "brightness" function for pixel colours. If you have
>> saturation on u8 arithmetic, you could write it as :
>>
>> u8 brightness(u8 red, u8 green, u8 blue) {
>> return red + green + blue;
>> }
>>
>> If you had two's complement wrapping on overflow, it would be completely
>> wrong. Agreed so far?
>
> I would say the algorithm is wrong already. The colors r,g,b
> account for 35%, 54% and 11% relative intensity of light, so
> you cannot perform the logic you have above appropriately.
>
> It would need to be:
>
> u8 brightness(u8 r, u8 g, u8 b) {
> return((u8)((f32)r*0.34f + (f32)g*0.54f + (f32)b*0.11f));
>
> In the case of the proper algorithm, there's no issue. :-)

The "real" algorithm for brightness is utterly irrelevant to the example.

>
>> One possible way to allow programmers to choose overflow behaviour,
>> between saturation and wrapping, would be to have a command-line switch.
>> This may sound like a fine idea, letting programmers choose the default
>> behaviour they want.
>
> I allow this feature by enclosing the block that is to operate
> as C does in a _c {..} block, a _c {{..}} block, or a _c {{..
> }(_c)} non-aligning-block.
>
> It can be messy in source code, but in the GUI editor it makes
> it more tolerable and visual.
>
> u8 brightness(u8 red, u8 green, u8 blue) {
> _c {
> return red + green + blue;
> }
> }
>
> In this case, no auto-promotion, and things will wrap as they
> do in C. Other examples:
>
> u8 brightness(u8 red, u8 green, u8 blue) {
> _c {{
> return red + green + blue;
> }}
> }
>
> u8 brightness(u8 red, u8 green, u8 blue) {
> _c {{ return red + green + blue; }(_c)}
> }
>

That is just getting more and more obscure, and I cannot see any purpose
in it.
All I can say here is that it makes C++ template syntax look clear and
intuitive :-)

>> But then the same source code does something entirely different
>> depending on the command-line switch. If you copy-and-paste the same
>> function source code into a different file, it might result in different
>> behaviour, depending on the switches used for that compilation. If you
>> look at the code in isolation, you can't tell if it is right or wrong,
>> or know that it relies on a particular choice of overflow behaviour.
>>
>> This is /bad/.
>
> Each source file is compiled using whatever options it should.
> CAlive allows a settings input file for options, so they don't
> have to be specified individually on a command line, but a single
> file with options is provided.
>

That is completely missing the point.

>> On the other hand, if the function is written:
>>
>> sat u8 brightness(sat u8 red, sat u8 green, sat u8 blue) {
>> return red + green + blue;
>> }
>>
>> or :
>>
>> u8 brightness(u8 red, u8 green, u8 blue) {
>> return sat_add(red, green, blue);
>> }
>>
>> or :
>>
>> u8 brightness(u8 red, u8 green, u8 blue) {
>> return red +.sat green +.sat blue;
>> }
>>
>> Then the code is clear, and it stands by itself. (I have no opinions as
>> to which syntax is best - you pick.)
>
> I have ways to do this already.

If you are using code syntax to control the choices of behaviour on
overflow, rather than command-line switches, then we are in agreement.
I may feel that your syntax looks like the cat has sat on the keyboard,
but we are agreed on the principle.

>
>> Do you see what I am getting at here?
>>
>>
>> Things like optimisation or warning choices are fine for command-line
>> switches - they affect the quality and efficiency of the generated code,
>> but not its correctness.
>
> Of course. And it's as it should be in my opinion.
>
>>> There have to be ways to turn things on or off. They can
>>> be added as something like a #pragma in source code, but to
>>> limit the ability to add compiler command-line switches,
>>> which allow external tools to use their various settings
>>> however they do to then be translated and conveyed through
>>> a standard protocol ... it's absolutely wrong advice. I'm
>>> amazed any intelligent developer would suggest it, unless
>>> they were on an agenda to give out wrong advice as per that
>>> agenda.
>>>
>>
>> You know fine that I do not have an agenda of giving out wrong advice.
>
> I do not know this. You often give out bad advice.

I am sure I have been wrong on occasion - but I have never knowingly
given bad advice. You confuse "does not agree with Rick" with "bad".

The same applies to advice I give to Bart regarding his language or
variations of C. There are often disagreements there too. But I like
to think that he knows my advice is given with the best of intentions
and based on my knowledge and experience, even when we disagree.

Paavo Helde

unread,
Sep 19, 2018, 9:28:08 AM9/19/18
to
On 19.09.2018 14:05, Bart wrote:
>
> (I've looked at a compiler where I've recently got rid of C-style
> promotions to 'int', which introduced all sorts of complications.
>
> There, with mixed integer operands (of size and type), I only widen one
> to be the same width as the other, with signed always dominant. So
> u16+i8 is done as i16. Not i32. And u8+i8 would be i8.
>
> There are already so many issues working with such mixed int types, that
> 65535+1 giving zero here is a minor one. It is just necessary to take
> care working with narrow types.)

Interesting. I have an example from the other extreme. We have a
scripting language with similar problems. However, this only concerns
vector arithmetics, there are no int8 scalars or such. So, on the script
level the script writer only writes something like

result = image1+2*image2;

and does not care about the types at all. The current underlying
implementation finds the best fitting result type dynamically by the min
and max values of the operand vectors and then performs the calculation
in chosen types.

This still leaves a choice between signed and unsigned types. A min/max
of 0 and 500 might be placed both in uint16 and int16. Currently
unsigned types are preferred, but this is just because our work
originates from image processing where unsigned types are more common.

There is no overflow and no wrapover, if the values do not fit into
int64 or uint64 any more the results will be converted over to double,
and if the values keep increasing eventually they might become inf.

Rick C. Hodgin

unread,
Sep 19, 2018, 9:33:54 AM9/19/18
to
On 9/19/2018 9:21 AM, David Brown wrote:
> On 19/09/18 15:00, Rick C. Hodgin wrote:
>> On 9/19/2018 8:36 AM, David Brown wrote:
>>> On 19/09/18 13:55, Rick C. Hodgin wrote:
>
>>> To be brutally honest, I /much/ prefer a syntax like this second one to
>>> your casks ... With the expanded "C" version, it is clear.
>>
>> Code it that way. CAlive allows you to code it the first way
>> and auto-injects that code for you.
>
> In programming, you spend a fraction of your time writing - and a lot
> more time reading. It does not help me if /I/ choose not to use casks,

In CAlive, you can look at the C code the RDC compiler generates
from the CAlive code. It's a Ctrl+Alt+Right operation in the GUI
editor. You can also hit Ctrl+Alt+Right again and see the B code,
and Ctrl+Alt+Right again and see the assembly, and then go back
again.

It's a "traipsing through the <strike>tulips</strike>code" ex-
perience.

For real, David, you don't have CAlive in front of you. You do
not know its capabilities, but have only seen snippets of its
capabilities likely mis-translated by what I intended to mean
in what I wrote, and what you believed it to mean when you read
it back.

Until you see it, you're only making yourself look like a fool
by summarily discounting the things I've considered greatly,
because you do not give my consideration any degree of weight.

>> Each source file is compiled using whatever options it should.
>> CAlive allows a settings input file for options, so they don't
>> have to be specified individually on a command line, but a single
>> file with options is provided.
>
> That is completely missing the point.

I understood your point. I think your viewpoint is wrong,
because I think compiler switches exist for a reason and
they are to be employed properly.

In a shop, you could rebuild an engine with a torque wrench
and an impact wrench. You grab the wrong tool and you'll
snap the bolts off when you go to tighten them.

The proper tool for the proper job, sir. We're not in the
business of hand-holding developers. We're in the business
of well-equipping them to thrive.

>>> You know fine that I do not have an agenda of giving out wrong advice.
>>
>> I do not know this. You often give out bad advice.
>
> I am sure I have been wrong on occasion - but I have never knowingly
> given bad advice. You confuse "does not agree with Rick" with "bad".

No, I don't. I know there are legitimate points of disagree-
ment, but there are also times you give out bad advice because
you do not know the other facets of CAlive I have already con-
sidered. You're using a peephole window looking at something
large and concluding there are wrong aspects of its design be-
cause you haven't yet seen the whole thing and can't envision
it.

Wait until CAlive is released before discrediting its features.
It is an integrated design of immense complexity and size. I
estimate it will take some time to truly appreciate ... even
for me and I wrote it (from that timeframe's point of view).

> The same applies to advice I give to Bart regarding his language or
> variations of C. There are often disagreements there too. But I like
> to think that he knows my advice is given with the best of intentions
> and based on my knowledge and experience, even when we disagree.

I think the problem here is this is a C forum, and you're
giving advice based on how C does things.

I'll see about starting up a CAlive forum. There is already
a Google Group. I'll start up another one for general discus-
sion and posting.

--
Rick C. Hodgin

bol...@cylonhq.com

unread,
Sep 19, 2018, 9:39:34 AM9/19/18
to
On Wed, 19 Sep 2018 09:04:03 -0400
"Rick C Hodgin" <rick.c...@gmail.com> wrote:
>CAlive uses promotion on nearly every calculation. It sign-

What is this CAlive compiler/language, something you wrote? Nothing's coming
up in Google. Got a link?

Rick C. Hodgin

unread,
Sep 19, 2018, 9:45:16 AM9/19/18
to
It's a compiler being developed. You can read about its
features here:

https://groups.google.com/forum/#!forum/caliveprogramminglanguage

It has a planned release date of sometime around Christmas
2019.

Some backstory: I came to this C group back in 2014 wanting
some changes to C. I wanted C to add the basic class, to
allow for exceptions, and I had several new ideas that could
be added to the language.

I fought for a couple years to try and get people on board
with the idea of tweaking the language, and was shot down
coldly and flatly at all points.

So, in late 2015 I decided to begin making my own language
that would have the features I want. I've been working on
it ever since, and plan to have a version 0.x released
around Christmas 2019, with a true 1.0 stable release some-
time in 2020.

We'll see though. I have many things pulling at my time,
and I cannot code as fast as I used to.

--
Rick C. Hodgin

bol...@cylonhq.com

unread,
Sep 19, 2018, 10:29:07 AM9/19/18
to
On Wed, 19 Sep 2018 09:45:05 -0400
"Rick C Hodgin" <rick.c...@gmail.com> wrote:
>On 9/19/2018 9:39 AM, bol...@cylonHQ.com wrote:
>> On Wed, 19 Sep 2018 09:04:03 -0400
>> "Rick C Hodgin" <rick.c...@gmail.com> wrote:
>>> CAlive uses promotion on nearly every calculation. It sign-
>>
>> What is this CAlive compiler/language, something you wrote? Nothing's coming
>> up in Google. Got a link?
>
>It's a compiler being developed. You can read about its
>features here:
>
> https://groups.google.com/forum/#!forum/caliveprogramminglanguage

Looks interesting.

>Some backstory: I came to this C group back in 2014 wanting
>some changes to C. I wanted C to add the basic class, to

Perhaps comp.lang.c would have been better then rather than comp.lang.c++

>I fought for a couple years to try and get people on board
>with the idea of tweaking the language, and was shot down
>coldly and flatly at all points.

Clearly you didn't pray hard enough ;)

>So, in late 2015 I decided to begin making my own language
>that would have the features I want. I've been working on
>it ever since, and plan to have a version 0.x released
>around Christmas 2019, with a true 1.0 stable release some-
>time in 2020.
>
>We'll see though. I have many things pulling at my time,
>and I cannot code as fast as I used to.

Well good luck, but The Next C/C++ market is a crowded one. You're competing
against D, Rust, Swift and Go just of the top of my head, not to mention Java
and C#.

james...@alumni.caltech.edu

unread,
Sep 19, 2018, 10:35:21 AM9/19/18
to
On Tuesday, September 18, 2018 at 2:49:10 PM UTC-4, Rick C. Hodgin wrote:
> On 9/18/2018 2:36 PM, james...@alumni.caltech.edu wrote:
> > On Tuesday, September 18, 2018 at 1:29:04 PM UTC-4, Rick C. Hodgin wrote:
> > ...
> >> Interesting. FWIW, I think the C committee got it wrong.
> >
> > What a surprise.
>
> Wow. Really? Seriously, James ... don't you think
> they got it wrong too?

No, I don't think there's any unique "right" approach. Every approach has problems, it's just a matter of choosing which set of problems you prefer. I know the reasons the committee gave for their choice, and those reasons point out a real problem with the unsigned preserving rules. It's a judgement call whether those problems are more important than the problems that value-preserving rules cause. They may have gotten that judgement call wrong - but it was a judgement call made by a large diverse group containing both implementors and users of C. You've made it clear that you find the C standard nearly impenetrable, whereas they were the people who wrote it - I think you can safely assume that every single committee member had a much better understanding of the C standard than you do. So you should give serious consideration to the possibility that it's your judgement that's in error, rather than theirs.

In any event, it's a decision that was made 3 decades ago, and never reversed, and huge amounts of code have been written that depends upon that decision. The committee considers backwards compatibility to be sufficiently important that it's unlikely to ever reverse that decision. Therefore, my primary concern is understanding the rule, not figuring out whether a different rule would be better.

> It seems the UNIX folk thought it was a mistake, as
> they already had invested code and developer time in
> the other direction.

However, also notice that they didn't object strongly to the decision, and promptly re-designed their compilers to support the committee's decision.

...
> I don't even see a good argument for C's logic, other
> than that's the way some people were doing it.

So, you don't understand why anyone might have a problem with the way the following code (from the C FAQ, 3.19) would be handled under unsigned-preserving rules?

unsigned short us = 10;
int i = -5;
if(i > us)
printf("whoops!\n");

james...@alumni.caltech.edu

unread,
Sep 19, 2018, 10:39:23 AM9/19/18
to
On Wednesday, September 19, 2018 at 3:45:10 AM UTC-4, David Brown wrote:
...
> With hindsight, in the modern C world, signedness preserving promotion
> would be better for many people - I would prefer it myself. Actually, I

Note: the usual term was "unsigned preserving", correctly reflecting the fact that the rules were biased toward unsigned: they said that a + b must be unsigned if either a or b is unsigned.

Rick C. Hodgin

unread,
Sep 19, 2018, 10:42:01 AM9/19/18
to
On 9/19/2018 10:28 AM, bol...@cylonHQ.com wrote:
>> Some backstory: I came to this C group back in 2014 wanting
>> some changes to C. I wanted C to add the basic class, to
>
> Perhaps comp.lang.c would have been better then rather than comp.lang.c++

I post on both. Also comp.std.c back in the day.

>> I fought for a couple years to try and get people on board
>> with the idea of tweaking the language, and was shot down
>> coldly and flatly at all points.
>
> Clearly you didn't pray hard enough ;)

"No" is one of God's answers to prayer. Some others are:
"yes," "not yet," and "not this, but wait and see because
I have something else in mind for you."

I think CAlive as part of that "not this..." response when
I came here in 2014. If I had met with reception, even with
some partial reception, I probably never would've written
CAlive.

>> So, in late 2015 I decided to begin making my own language
>> that would have the features I want. I've been working on
>> it ever since, and plan to have a version 0.x released
>> around Christmas 2019, with a true 1.0 stable release some-
>> time in 2020.
>>
>> We'll see though. I have many things pulling at my time,
>> and I cannot code as fast as I used to.
>
> Well good luck, but The Next C/C++ market is a crowded one. You're competing
> against D, Rust, Swift and Go just of the top of my head, not to mention Java
> and C#.

Thank you for your encouragement. It's pretty rare to hear
any positive things about CAlive. Most people feel more
comfortable attacking it, bashing it, attacking me, bashing
me, etc. But, I'm not writing CAlive specifically for other
people. I'm writing it for God, for me to use next, and for
other people to use last.

I want to honor God with my time, my labor, and the abilities
He first gave me.

I'm writing CAlive to be a Christian offering unto God from
inception. It's not just to be another language. I want to
give back to God fruit from the natural talents and abilities
He first gave me. I want my life on this Earth to be a re-
flection of His Son living within me, that I may return to
Him something of what He first gave me, and explicitly to Him
by name, by reference, by praise, by adoration, in love, in
thanksgiving.

My goal is to first honor Him with this work, and to give it
to other people who would like to use a tool that's been lifted
up to Him throughout its design in prayer, in seeking to please
Him, rather than simply being written and maintained by people
who have the ability, but who do not directly honor God with
their lives. For people who want a purified, sanctified tool
to use, one they can be proud to support in their faith because
those who will work on it from the beginning through to the end
will be doing so because they want to honor Jesus Christ with
their lives.

It's also a teaching tool, to show people that they too can
honor God with their skills and talents in this world, and even
as a forefront, first-level offering, out there, visible to all,
and it will not only succeed with endurance and patience, but
it will be a huge blessing to many people to give the fruits of
their labor over to Him and them in that way.

--
Rick C. Hodgin

Rick C. Hodgin

unread,
Sep 19, 2018, 10:49:54 AM9/19/18
to
On 9/19/2018 10:35 AM, james...@alumni.caltech.edu wrote:
> On Tuesday, September 18, 2018 at 2:49:10 PM UTC-4, Rick C. Hodgin wrote:
>> On 9/18/2018 2:36 PM, james...@alumni.caltech.edu wrote:
>>> On Tuesday, September 18, 2018 at 1:29:04 PM UTC-4, Rick C. Hodgin wrote:
>>>> Interesting. FWIW, I think the C committee got it wrong.
>>> What a surprise.
>> Wow. Really? Seriously, James ... don't you think
>> they got it wrong too?
>
> No, I don't think there's any unique "right" approach. Every approach has problems, it's just a matter of choosing which set of problems you prefer. I know the reasons the committee gave for their choice, and those reasons point out a real problem with the unsigned preserving rules. It's a judgement call whether those problems are more important than the problems that value-preserving rules cause. They may have gotten that judgement call wrong - but it was a judgement call made by a large diverse group containing both implementors and users of C. You've made it clear that you find the C standard nearly impenetrable, whereas they were the people who wrote it - I think you can safely assume that every single committee member had a much better understanding of the C standard than you do. So you should give serious consideration to the possibility that it's your judgement that's in error, rather than theirs.
>
> In any event, it's a decision that was made 3 decades ago, and never reversed, and huge amounts of code have been written that depends upon that decision. The committee considers backwards compatibility to be sufficiently important that it's unlikely to ever reverse that decision. Therefore, my primary concern is understanding the rule, not figuring out whether a different rule would be better.

The only way CAlive will ever support C90 and C99 compliance
is if someone comes on board who understands all that stuff
and gives me a list of changes that need to be made, or a
list of rules which need to be followed.

I will never be able to read the C Standard document and de-
cipher its nuances sufficiently to approach it. My brain
simply does not work that way.

>> It seems the UNIX folk thought it was a mistake, as
>> they already had invested code and developer time in
>> the other direction.
>
> However, also notice that they didn't object strongly to the decision, and promptly re-designed their compilers to support the committee's decision.

I bet many of them did. :-) But you cannot fight against the
C committee. It's like trying to strike the wind. It just
ignores your efforts and laughs at your wasted expenditure of
energy ... at least that's been my experience.

> ...
>> I don't even see a good argument for C's logic, other
>> than that's the way some people were doing it.
>
> So, you don't understand why anyone might have a problem with the way the following code (from the C FAQ, 3.19) would be handled under unsigned-preserving rules?
>
> unsigned short us = 10;
> int i = -5;
> if(i > us)
> printf("whoops!\n");

Promotion to signed in this case is proper, because when you're
dealing with signed / unsigned operators, you have to promote to
signed values. That is a natural thing to do.

It's in the cases where you have unsigned lesser size to unsigned:

unsigned char a = 3, b = 3, c = 3;
unsigned int d = 10;
if (a + b + c < d)
printf("Go go Gadget Promotion!\n");

The "a + b + c" should not be promoted to a signed value. That's
where the C committee got it wrong. Since the operator is unsigned
it should've been promoted to unsigned, and when the unsigned pro-
motion reached the < operator, it should've then looked at the RHS
value and determined if another promotion to signed was required.

I don't see how anyone can find fault with that logic, save from
the one perspective that it's the way C works today, and therefore
it's wrong from that one perspective.

In any event, CAlive will reverse that decision made by the C
committee some 30+ years ago. Dare I to be so bold? Why yes,
yes I do dare.

--
Rick C. Hodgin

james...@alumni.caltech.edu

unread,
Sep 19, 2018, 11:38:38 AM9/19/18
to
On Wednesday, September 19, 2018 at 10:49:54 AM UTC-4, Rick C. Hodgin wrote:
...
> I will never be able to read the C Standard document and de-
> cipher its nuances sufficiently to approach it. My brain
> simply does not work that way.

Your comment above probably has a lot to do with the experience you
describe below:

> I bet many of them did. :-) But you cannot fight against the
> C committee. It's like trying to strike the wind. It just
> ignores your efforts and laughs at your wasted expenditure of
> energy ... at least that's been my experience.

People capable of understanding the standard generally get much better
results when they propose changes to it than those who do not - which
strikes me as both eminently reasonable, and positively desirable.

Rick C. Hodgin

unread,
Sep 19, 2018, 11:43:29 AM9/19/18
to
I have no doubts. My approach is not commensurate with the needs
of the people in the C committee, and I was told that by many people
during that time in 2014/2015. You may have been one of them.

It's not the way I work, so modifying C is not within my ability.
As such ... CAlive.

--
Rick C. Hodgin

Ben Bacarisse

unread,
Sep 19, 2018, 11:51:08 AM9/19/18
to
"Rick C. Hodgin" <rick.c...@gmail.com> writes:

> ... But you cannot fight against the
> C committee. It's like trying to strike the wind. It just
> ignores your efforts and laughs at your wasted expenditure of
> energy ... at least that's been my experience.

What experience have you had interacting with WG14 (the ISO C
committee)? I was not aware that you'd had any dealings with the
committee at all. I'd be interested to know what happened.

(I've set followup-to: comp.lang.c since this is a C matter not a C++
one.)

--
Ben.

Robert Wessel

unread,
Sep 19, 2018, 1:10:32 PM9/19/18
to
Actually there is a solution, although it's clearly not one that could
work in the context of C or C++ (well, you can do some of this with
C++, but not for the basic types).

There are clearly needs for different classes of arithmetic. You have
proper arithmetic (one's that actually perform more or less as you'd
expect numbers to behave from the rules of arithmetic - more or less
these need to generate larger intermediate results as necessary to
complete the computation *correctly* - perhaps you'd prefer the term
rational) types, integer types with various ranges and overflow
characteristics (signed unsigned, wrapping, saturating, trapping),
floating and complex types (possibly in a couple of formats), and if
you really want, I'll concede quaternions. We can come up with a few
more as well - for example we might have scaled arithmetic types.

So there need to be a few ground rules. A hard rule is that there
should be no implicit value losing conversions. This would, for
example allow an implicit conversion from a uint8 to an int16, as well
as all the normal widenings. C's poorly defined sizes make applying
that rule problematic in any event.

I prefer a somewhat stronger rule that in general there are no
conversions between classes of numbers, with a few possible
exceptions. Thus you can't add a uint8 and an int16 without
explicitly specifying a conversion for one of them, but you can add an
int8 and an int16 (with the former being promoted implicitly).

An even stronger rule is possible, not allowing any implicit
conversions, even simple widenings, but that seems too strict to me.

Obviously different classes of numbers will allow different operations
(for example, floating and arithmetic types don't allow boolean
operations).

A crucial point is that assignment is also limited, and most narrowing
assignments are not allowed without an explicit conversion. Some
might be allowed (for example, a sat16 result has an obvious
conversion to a sat8, arithmetic types narrow naturally, but would
require overflow handling). Of course there are no implicit
conversions between classes at assignment either.

Also required is a way of handling overflows and exceptions, and those
can be considered part of the explicit conversions. In many cases it
might only be the specification of how to handle the overflow (you
might generically specify that a saturated or wrapping number gets
narrowed in the normal way).

I'm not a stickler for absolute purity, there may be well defined, and
useful, exceptions to the "no implicit conversion" rule. For example,
converting a floating type to a complex (at least with a cartesian
complex) is risk free and actually fairly common. On the other hand,
I'm not willing to add a great deal of complexity to support that.

And since the subject of literals has come up, you can deal with those
too, without having to explicitly type all of them - any literal has a
partial type that doesn't get fully established until it's combined
with something. Thus a "-300" could turn into a sat16, int16 or the
like, as well as a float, but could not turn into an unsigned type, or
any 8-bit type. "3.4" could become a floating or complex type, but
not any integer type (if we allowed scaled arithmetic types, it might
become one of those as well).

As a general comment, *most* math should get done with
arithmetic/rational or floating types, and the integer types would
serve more specialized purposes.

Well, my rant for the day...

Mr Flibble

unread,
Sep 19, 2018, 3:24:57 PM9/19/18
to
On 19/09/2018 15:49, Rick C. Hodgin wrote:

> In any event, CAlive will reverse that decision made by the C
> committee some 30+ years ago.  Dare I to be so bold?  Why yes,
> yes I do dare.

Nobody cares. Your CAlive programming language is as batshit crazy as you
are. Maybe you should suggest it to the TempleOS guy as he is as batshit
crazy (and bigoted) as you.

/Flibble

--
"Suppose it’s all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I’d say, bone cancer in children? What’s that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It’s not right, it’s utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That’s what I would say."

David Brown

unread,
Sep 19, 2018, 4:47:04 PM9/19/18
to
On 19/09/18 15:33, Rick C. Hodgin wrote:
> On 9/19/2018 9:21 AM, David Brown wrote:
>> On 19/09/18 15:00, Rick C. Hodgin wrote:
>>> On 9/19/2018 8:36 AM, David Brown wrote:
>>>> On 19/09/18 13:55, Rick C. Hodgin wrote:
>>
>>>> To be brutally honest, I /much/ prefer a syntax like this second one to
>>>> your casks ... With the expanded "C" version, it is clear.
>>>
>>> Code it that way.  CAlive allows you to code it the first way
>>> and auto-injects that code for you.
>>
>> In programming, you spend a fraction of your time writing - and a lot
>> more time reading.  It does not help me if /I/ choose not to use casks,
>
> In CAlive, you can look at the C code the RDC compiler generates
> from the CAlive code.  It's a Ctrl+Alt+Right operation in the GUI
> editor.  You can also hit Ctrl+Alt+Right again and see the B code,
> and Ctrl+Alt+Right again and see the assembly, and then go back
> again.
>
> It's a "traipsing through the <strike>tulips</strike>code" ex-
> perience.
>
> For real, David, you don't have CAlive in front of you.  You do
> not know its capabilities, but have only seen snippets of its
> capabilities likely mis-translated by what I intended to mean
> in what I wrote, and what you believed it to mean when you read
> it back.

You are correct that I don't have CAlive in front of me - I base my
responses to your posts entirely on your posts. If I get the wrong
impression of it sometimes, there is only one person who could help that.

I have experience with a /lot/ of programming languages. I estimate I
have had some use of nearly two dozen over the years - though I would
not claim to know many of them very well. I have used a few of these
that /required/ a gui of some sort for development. And without
exception, the more the gui was required, the less practical the
language for real, serious work. There is no substitute from being able
to read and write the code in normal letters using a normal keyboard and
a normal editor.

Now, a good gui and IDE makes the job much easier - C development is
greatly aided by an editor with syntax highlighting, code completion,
navigation between identifiers and their definitions or declarations,
and so on. There is no doubt that I am much more productive working
with Eclipse than with Notepad.

But my experience is that to be useful as a good programming language,
it should be possible to work with code as text. It should be possible
to take a function in the language, and post it as text in a newsgroup
post - and have people understand it. It should not need different
coloured bits to be comprehensible. It should not need you to click on
different bits to see what it does, or hold your mouse over it to expand
sections to see how they work. It should not need to be translated to
C, assembly, or anything else to make its meaning clear.

This is, of course, merely my opinion.

>
> Until you see it, you're only making yourself look like a fool
> by summarily discounting the things I've considered greatly,
> because you do not give my consideration any degree of weight.
>
>>> Each source file is compiled using whatever options it should.
>>> CAlive allows a settings input file for options, so they don't
>>> have to be specified individually on a command line, but a single
>>> file with options is provided.
>>
>> That is completely missing the point.
>
> I understood your point.  I think your viewpoint is wrong,
> because I think compiler switches exist for a reason and
> they are to be employed properly.

No, you have misunderstood it. I /agree/ that compiler switches can be
used usefully.

But they can also be /abused/. If code is dependent on compiler
switches for correctness, and the switches affect how the same source
text behaves, then that is a bad thing. Code functionality should - as
much as possible - be determined by the code written, not by things
outside it.

From what you wrote about the way you handle choices about overflows,
using casks, it sounds like you /agree/ with me here. That's why I say
you misunderstand my point.

>
>>>> You know fine that I do not have an agenda of giving out wrong advice.
>>>
>>> I do not know this.  You often give out bad advice.
>>
>> I am sure I have been wrong on occasion - but I have never knowingly
>> given bad advice.  You confuse "does not agree with Rick" with "bad".
>
> No, I don't.  I know there are legitimate points of disagree-
> ment, but there are also times you give out bad advice because
> you do not know the other facets of CAlive I have already con-
> sidered.  You're using a peephole window looking at something
> large and concluding there are wrong aspects of its design be-
> cause you haven't yet seen the whole thing and can't envision
> it.

The peephole I use is the one you give me. You know fine I will not be
clicking on any video links, nor will I be downloading CAlive. You make
posts here, I respond to them. If there are things about CAlive that
are relevant and that I am missing, you need to tell me. I comment on
the /language/ - the text you show here - not the IDE or development
environment.

>
> Wait until CAlive is released before discrediting its features.
> It is an integrated design of immense complexity and size.  I
> estimate it will take some time to truly appreciate ... even
> for me and I wrote it (from that timeframe's point of view).
>
>> The same applies to advice I give to Bart regarding his language or
>> variations of C.  There are often disagreements there too.  But I like
>> to think that he knows my advice is given with the best of intentions
>> and based on my knowledge and experience, even when we disagree.
>
> I think the problem here is this is a C forum, and you're
> giving advice based on how C does things.
>

(It has ended up in the C++ newsgroup, but that is a minor detail.)

You have positioned CAlive as a "next generation C", or "evolved C", or
some kind of replacement for C. Of course its comparison to C is
relevant. C is our common language for reference - it would not help
you much if I compared it to Forth, or Haskell. And it is an imperative
programming language with a similar structure to C - a comparison to
other imperative languages, such as Pascal, might be useful if you like.

I think C is a fine programming language, and I have used it happily for
many projects. However, I think that if I were designing a new language
to handle similar tasks, there are many things I would do differently -
hindsight is an excellent tool. But I also think there are many things
I would keep the same.

Since you are targeting CAlive as a language related to C, or covering
some of the uses of C, it makes sense to discuss them.

David Brown

unread,
Sep 19, 2018, 5:01:27 PM9/19/18
to
What have you got against octonions, may I ask? More realistically,
fixed point numbers of various sizes are very much in use, especially in
embedded systems. There was an attempt at a supplementary C standard
for embedded coding (N1169) which included them, but IMHO it was
seriously badly thought out. Types like "_Sat unsigned short _Fract"
are utterly useless to embedded programmers - they need to have exact sizes.


> So there need to be a few ground rules. A hard rule is that there
> should be no implicit value losing conversions. This would, for
> example allow an implicit conversion from a uint8 to an int16, as well
> as all the normal widenings. C's poorly defined sizes make applying
> that rule problematic in any event.

Agreed. /Most/ of C's implicit conversions are value-preserving, but
not all. In particular, some conversions turn a signed type into an
unsigned type, which could easily be wrong.

>
> I prefer a somewhat stronger rule that in general there are no
> conversions between classes of numbers, with a few possible
> exceptions. Thus you can't add a uint8 and an int16 without
> explicitly specifying a conversion for one of them, but you can add an
> int8 and an int16 (with the former being promoted implicitly).
>

You can get most of this today with gcc, using the "-Wconversion
-Wsign-conversion" warnings (perhaps promoting them to errors).
All this could be handled by a series of C++ classes. It would be quite
a bit of work in total, but it should all be possible.

> As a general comment, *most* math should get done with
> arithmetic/rational or floating types, and the integer types would
> serve more specialized purposes.
>

As an embedded programmer working on small systems, most maths should be
done with integers! (But I get your point.)

Mr Flibble

unread,
Sep 19, 2018, 6:47:36 PM9/19/18
to
On 19/09/2018 20:24, Mr Flibble wrote:
> On 19/09/2018 15:49, Rick C. Hodgin wrote:
>
>> In any event, CAlive will reverse that decision made by the C
>> committee some 30+ years ago.  Dare I to be so bold?  Why yes,
>> yes I do dare.
>
> Nobody cares. Your CAlive programming language is as batshit crazy as you
> are.  Maybe you should suggest it to the TempleOS guy as he is as batshit
> crazy (and bigoted) as you.

Alas it seems Terry A Davis has passed away (struck from the back and
killed by a Union Pacific train).
http://www.thedalleschronicle.com/news/2018/sep/07/man-killed-train-had-tech-following/
His demons can torment him no more. R.I.P.

Richard Damon

unread,
Sep 20, 2018, 6:31:50 AM9/20/18
to
On 9/18/18 3:45 PM, Rick C. Hodgin wrote:
> On 9/18/2018 3:41 PM, Anton Shepelev wrote:
>> Let me impersonate a C guru and quote the standard:
>>
>>    If an int can represent all values of the original type,
>>    the value is converted to an int; otherwise, it is
>>    converted to an unsigned int.
>
> What is the logic behind that?  You've moved from unsigned to
> signed for no reason other than it will fit in the positive
> portion of the signed's range.
>
> It was originally unsigned for a reason.  Why migrate it to
> signed without a cast?
>
> I honestly consider this a fundamental flaw in C (and C++).
>

Decades ago the Standards Committee came across this issue, how should
unsigned values smaller than int, be handled, and there were strong
arguments on both sides, should the unsignedness be preserved or not.
Pre-Standard implementations existed with both decisions, so it was
going to be a quiet possibly breaking change to someone. It had enough
importance that it really couldn't be left to be unspecified or even
implementation defined, so after much heated arguments, they decided on
the current rule, over the objections of some of the members of the
community.

Rick C. Hodgin

unread,
Sep 20, 2018, 8:23:03 AM9/20/18
to
I've been trying to think of what the advantages would be with a
promotion to signed, and I'm not seeing it ... unless the operator
it's going to be working with is also signed. But in a straight-
forward unsigned to unsigned comparison, such as the one I had
which flagged this question in the first place ... I cannot see
it.

I would argue the C committee didn't do what they should've. They
should've modified the standard to allow unsigned promotion for
all unsigned values, and then only promote to signed when the op
on the other side requires it.

And I honestly can't think of a reason why that's not the only
logical choice. I'd be open to hearing some reasons.

--
Rick C. Hodgin

Tim Rentsch

unread,
Sep 22, 2018, 9:32:29 AM9/22/18
to
My understanding is that the cases under discussion were only
those involving promotion of types narrower than int to one of
{int, unsigned int} - that is, what the Standard terms "integer
promotions". An unsigned int added to a long, for example, would
still be a signed type, not an unsigned type (assuming unsigned
int is narrower than long).

(The Rationale document also mentions the typing of integer
constants, but that has no bearing on the above remarks.)
0 new messages