How would you design C's replacement?

J

James Kuyper

On 05/02/2012 05:36 AM, BartC wrote:
....
And the fix is easy: use different symbols for assignment and equality. By
using the natural "=" symbol for equality, you won't then fall into the trap
of using it by mistake instead of the very 1970s-looking "==".

Or use two symbols for assignment; one that returns the value of the left
side ("="), and one which returns void (eg. ":="). This could be added to C
today. It won't eliminate the problem, but can reduce it.

At a more formal level, I've sometimes considered making assignment a
statement type, rather than an expression type. As a statement that is
not an expression, it would not return a value, and would therefore
never be confusable with equality comparisons. I almost never use the
return value from a assignment expression, so I don't see this as a
significant loss.
This is only for a new C-like language, of course; it would break too
much existing C code to make such a modification to C.
 
J

Jens Gustedt

Am 05/02/2012 08:02 AM, schrieb Ian Collins:
It can where the type can be deduced, the standard uses an example:

auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>

You mean the C++ states this, I suppose. Could you translate that into
something for C? int[2]?
Something simple like

auto x = {1};

is also OK.

Is it int or int[1] ?
This wouldn't work, but in that case there is nothing to be gained with
auto (you had to name the type in the cast).


But you still have to name the type somewhere in the statement.

An application of all this would be something where you have a macro for
initialisation, say

#define TOTO_INITIALIZER(X) (toto){&(X)}

Then

auto y = TOTO_INITIALIZER(y);

would avoid to give the type twice. Nowadays such macros in C look more like

#define TOTO_INITIALIZER(X) {&(X)}

with only implicit mention of the type and then

toto y = TOTO_INITIALIZER(y);

will not check for consistence.

Jens
 
J

James Kuyper

Am 05/02/2012 08:02 AM, schrieb Ian Collins:
It can where the type can be deduced, the standard uses an example:

auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>

You mean the C++ states this, I suppose. Could you translate that into
something for C? int[2]?

std::initializer_list<> is a relatively new standard library template.
It's too new for me to be very familiar with it; I stopped paying close
attention to the C++ standard around the time they started preparing the
2003 standard. Key sections mentioning initializer lists seem to be
8.5.4,13.3.3.1.5, and 18.9. I've no idea whether the concept could or
should be adapted to C; I think that C might need to take a simpler
approach to the cases where C++ relies upon initializer lists.
 
J

jacob navia

Le 02/05/12 16:35, James Kuyper a écrit :
Am 05/02/2012 08:02 AM, schrieb Ian Collins:
It can where the type can be deduced, the standard uses an example:

auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>

You mean the C++ states this, I suppose. Could you translate that into
something for C? int[2]?

std::initializer_list<> is a relatively new standard library template.
It's too new for me to be very familiar with it; I stopped paying close
attention to the C++ standard around the time they started preparing the
2003 standard. Key sections mentioning initializer lists seem to be
8.5.4,13.3.3.1.5, and 18.9. I've no idea whether the concept could or
should be adapted to C; I think that C might need to take a simpler
approach to the cases where C++ relies upon initializer lists.


Excuse me but how should that work?

auto foo = 45;

What should that be?

char, short, int, long long, unsigned char, unsigned short, unsigned int
or unsigned long long?

ALL those types qualify actually. Even float and double qualify also.

And this:

auto x = 'a';

Is that a char? an int?

And what would the users gain from such a construct?
In C++ with the template stuff it is maybe necessary, but in C???
 
B

Ben Bacarisse

Jens Gustedt said:
Am 05/02/2012 08:02 AM, schrieb Ian Collins:
It can where the type can be deduced, the standard uses an example:

auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>

You mean the C++ states this, I suppose. Could you translate that into
something for C? int[2]?

I think Ian was just answering the assertion that you can't use auto
with an {} list. There is no real translation into C because x1 is not
an array of ints (or even a std::vector<int>) but an object of a
specific type intended to be used as an argument to a constructor. It's
a lovely feature (you can have native-looking initialisers for
user-defined types) but you don't get an array out it.

The type std::initializer_list<T> does implement std::begin(), giving
you a random-access iterator (specifically a const T *), but that's not
quite the same thing. This C++:

auto a = std::begin({1, 2, 3});

is very much like this C:

int *a = (int[]){1, 2, 3};

which could be "tidied up" to

auto a = (int[]){1, 2, 3};

if C had C++'s meaning of auto. However, you'd probably want to do
something more like this:

auto x[] = {1, 2};

where the size of the array is determined by the length of the list, and
the type by some rule applied to the types of the list members (the
"largest"? the "widest"? ...?). Without other changes, or some
complexity in the type-guessing rule,

auto s[] = {'a', 'b', 'c', '\0'};

(and by extension auto s[] = "abc";) would make the elements of s ints
not chars.

<snip>
 
R

Rui Maciel

BartC said:
That's being a little elitist. Why shouldn't anyone be able to use the
language, for example those who have to program other languages too?

I believe the point was that experienced programmes hardly make the mistake
of doing (a = b) instead of (a == b). It's hardly elitist to say that
experienced programmers do some errors less frequently than less experienced
ones.

And the fix is easy: use different symbols for assignment and equality. By
using the natural "=" symbol for equality, you won't then fall into the
trap of using it by mistake instead of the very 1970s-looking "==".

Or use two symbols for assignment; one that returns the value of the left
side ("="), and one which returns void (eg. ":="). This could be added to
C today. It won't eliminate the problem, but can reduce it.

If the problem is that people mistake the '==' token for the '=' token, if
you introduce another token to be used as an assignment operator then not
only the original problem isn't solved but I also suspect that it actually
increases the odds that this sort of mistake will be made.


Rui Maciel
 
R

Rui Maciel

James said:
At a more formal level, I've sometimes considered making assignment a
statement type, rather than an expression type. As a statement that is
not an expression, it would not return a value, and would therefore
never be confusable with equality comparisons. I almost never use the
return value from a assignment expression, so I don't see this as a
significant loss.
This is only for a new C-like language, of course; it would break too
much existing C code to make such a modification to C.

If someone really needs some hand-holding with the assignment operator, a
macro could help. The following macro might do the trick:

#define SET(A,B) { A = B; }


I don't believe this sort of solution will ever be popular.


Rui Maciel
 
B

BGB

Le 02/05/12 16:35, James Kuyper a écrit :
Am 05/02/2012 08:02 AM, schrieb Ian Collins:

It can where the type can be deduced, the standard uses an example:

auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>

You mean the C++ states this, I suppose. Could you translate that into
something for C? int[2]?

std::initializer_list<> is a relatively new standard library template.
It's too new for me to be very familiar with it; I stopped paying close
attention to the C++ standard around the time they started preparing the
2003 standard. Key sections mentioning initializer lists seem to be
8.5.4,13.3.3.1.5, and 18.9. I've no idea whether the concept could or
should be adapted to C; I think that C might need to take a simpler
approach to the cases where C++ relies upon initializer lists.


Excuse me but how should that work?

auto foo = 45;

What should that be?

AFAIK, absent anything else, the default type here is 'int'.

char, short, int, long long, unsigned char, unsigned short, unsigned int
or unsigned long long?

it defaults to int, as there is little reason for anything smaller.
int is sort of the "implicit default type" in C (though it is at least a
little more explicit in C99, "implicit int" and similar tend to remain,
well, implicitly...).

long or long-long literals generally require suffixes, such as L or LL.

ALL those types qualify actually. Even float and double qualify also.

actually, no:
you only get float or double if it has a form like '1.0' or similar.

IIRC, in C it defaults to double in this case.

And this:

auto x = 'a';

Is that a char? an int?

probably, it would be char in C++, and int in C.

And what would the users gain from such a construct?
In C++ with the template stuff it is maybe necessary, but in C???

it is less clear.


my own language does something similar with declarations like "var x;"
where the compiler may attempt to infer the type, but with the
difference that the variable is not forced to use a single type over its
entire lifetime, but rather it is local to "a specific location in the
program".

so, assigning to a variable not only assigns a value at run-time, but
may also assign a type at compile-time, with some special handling for
"clashes".

all else fails, it uses dynamic types for the variable.
 
D

Dr Nick

Rui Maciel said:
I believe the point was that experienced programmes hardly make the mistake
of doing (a = b) instead of (a == b). It's hardly elitist to say that
experienced programmers do some errors less frequently than less experienced
ones.

I confess to doing it a couple of weeks ago. But whether it was a
sudden thinko of just a simple typo I don't know.

I've got GCC's warning such that it told me about it. Otherwise ...
 
B

BGB

I believe the point was that experienced programmes hardly make the mistake
of doing (a = b) instead of (a == b). It's hardly elitist to say that
experienced programmers do some errors less frequently than less experienced
ones.

yeah, it is rare and almost invariably due to a typing error rather than
actually intending to type it that way. so, '==' becomes like
second-nature or something.

far more common problems are things like:
mistyping function names;
messing up the number or types of function arguments;
accidentally doing bad type conversions;
....

in GCC there were options to make the compiler reject the code more
readily in these cases, but annoyingly MSVC is a bit more prone to let
it through (usually just giving warnings), without options to turn up
the strictness.


this isn't to say that a person needs Java levels of strictness (where
every implicit type-conversion is an error, ...), but the compiler being
like "oh well, whatever" about implicit conversions between pointers and
integers or similar (or between incompatible pointer types) is probably
a bit too lax.

like, probably if the programmer just went and assigned a struct-pointer
into an integer variable without casting it, then it was probably a
typing error.

If the problem is that people mistake the '==' token for the '=' token, if
you introduce another token to be used as an assignment operator then not
only the original problem isn't solved but I also suspect that it actually
increases the odds that this sort of mistake will be made.

yeah, I like = and == the way they are.
I wouldn't mind too much if the compiler give a warning (or even an
error) if '=' were used directly in an 'if' conditional.

but, then again, it isn't really a common error.
 
B

BartC

BGB said:
On 5/2/2012 8:16 AM, Rui Maciel wrote:


yeah, I like = and == the way they are.
I wouldn't mind too much if the compiler give a warning (or even an error)
if '=' were used directly in an 'if' conditional.

but, then again, it isn't really a common error.

I do it all the time, when writing C code (which admittedly isn't that
often).

The two main compilers I use don't give a warning, not with the default
options anyway.

I write very little Python either, but the same mistake gets picked up
there, because "=" isn't allowed inside an expression.
yeah, I like = and == the way they are.

You get used to "=" for assignment (I spent a year writing Fortran once),
but it doesn't change the fact that "=" would have been first choice for an
equality operator.
 
I

Ian Collins

Le 02/05/12 16:35, James Kuyper a écrit :
Am 05/02/2012 08:02 AM, schrieb Ian Collins:

It can where the type can be deduced, the standard uses an example:

auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>

You mean the C++ states this, I suppose. Could you translate that into
something for C? int[2]?

std::initializer_list<> is a relatively new standard library template.
It's too new for me to be very familiar with it; I stopped paying close
attention to the C++ standard around the time they started preparing the
2003 standard. Key sections mentioning initializer lists seem to be
8.5.4,13.3.3.1.5, and 18.9. I've no idea whether the concept could or
should be adapted to C; I think that C might need to take a simpler
approach to the cases where C++ relies upon initializer lists.
And what would the users gain from such a construct?

A trivial example might be something like:

auto in = fopen("x", "r" );
auto out = fopen("y", "w+" );

char buf[64];

// what does fread return?
//
auto toWrite = fread( buf, sizeof(buf), 1, in );

if( toWrite )
{
auto written = fwrite( buf, sizeof(buf), 1, out );

if( written != toWrite ) { /* report error */ }
}
In C++ with the template stuff it is maybe necessary, but in C???

I agree the feature is much more important to C++ than to C, but handy
none the lass.
 
B

BGB

I do it all the time, when writing C code (which admittedly isn't that
often).

The two main compilers I use don't give a warning, not with the default
options anyway.

I write very little Python either, but the same mistake gets picked up
there, because "=" isn't allowed inside an expression.

presumably, it is mostly a matter of how much one gets used to the
language. with experience, a person gets very used to using == to
express equality, so much that it also tends to show up when writing
about other (non-programming) topics.

You get used to "=" for assignment (I spent a year writing Fortran
once), but it doesn't change the fact that "=" would have been first
choice for an equality operator.

possibly, but I think assignments are generally more common than
checking for equality, so it makes sense that assignment have the
shorter operator.

otherwise, the semantics of "=" could have been made context dependent,
but this would not necessarily have been better.
 
J

Jorgen Grahn

On 04/30/2012 11:22 AM, Malcolm McLean wrote:
...

No one has that "weight". If it needs to be forced on people - if it
can't gain acceptance except by reason of being mandated by a
sufficiently powerful authority - it can't be good enough to justify
mandating it.

That's an interesting point of view, but I think you're wrong. E.g.
I'd much rather have one imperfect strcmp() which everyone knows, than
constant fighting among groups who believe their way to compare
strings is The One Way To Compare Strings.

I don't see a lot of spontaneous consensus in programming.

/Jorgen
 
J

Jorgen Grahn

On 04/30/12 06:33 PM, Robert Wessel wrote: ....

C's ubiquity comes in various forms, not only as run anywhere but also
find a programmer anywhere.

Most of the embedded projects I have been involved with recently use gcc
and a decent subset of those used gcc and a Linux kernel. One of my
first questions I asked on joining those projects was "why don't you use
C++?" and the answer invariably boils down to "we use what we are
familiar with".

So if it's hard to find experienced developers for the most popular C
derived language, I'd hate to be the one promoting a new one!

Perhaps we should wish for better programmers instead of better
languages.

(In this specific case, better at picking up worthwhile new ideas.
I don't doubt those guys' C skills.)

/Jorgen
 
I

ImpalerCore

Le 02/05/12 16:35, James Kuyper a écrit :
On 05/02/2012 08:40 AM, Jens Gustedt wrote:
Am 05/02/2012 08:02 AM, schrieb Ian Collins:
It can where the type can be deduced, the standard uses an example:
auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>
You mean the C++ states this, I suppose. Could you translate that into
something for C? int[2]?
std::initializer_list<>   is a relatively new standard library template.
It's too new for me to be very familiar with it; I stopped paying close
attention to the C++ standard around the time they started preparing the
2003 standard. Key sections mentioning initializer lists seem to be
8.5.4,13.3.3.1.5, and 18.9. I've no idea whether the concept could or
should be adapted to C; I think that C might need to take a simpler
approach to the cases where C++ relies upon initializer lists.

And what would the users gain from such a construct?

A trivial example might be something like:

   auto in  = fopen("x", "r" );
   auto out = fopen("y", "w+" );

   char buf[64];

   // what does fread return?
   //
   auto toWrite = fread( buf, sizeof(buf), 1, in );

   if( toWrite )
   {
     auto written = fwrite( buf, sizeof(buf), 1, out );

     if( written != toWrite ) { /* report error */ }
   }
In C++ with the template stuff it is maybe necessary, but in C???

I agree the feature is much more important to C++ than to C, but handy
none the lass.

Handy perhaps, but detrimental to readability and troubleshooting.
Now I have to infer the type of each 'auto' variable by remembering
the return type of each function, as well as any conversions that may
happen under the hood. Without knowing exactly what 'fread' returns,
it's not clear whether the return type is a int, size_t, or even bool,
and from the context of the next 'if' statement, 'toWrite' could
easily be interpreted as the name of a boolean variable when it's
actually a 'size_t'.

I would not label this a "gain" for C. Your example is but a taste of
how bad 'auto' would be if used liberally.

Best regards,
John D.
 
M

Malcolm McLean

בת×ריך ×™×•× ×¨×‘×™×¢×™, 2 במ××™ 2012 20:26:28 UTC+1, מ×ת Bart:
You get used to "=" for assignment (I spent a year writing Fortran once),
but it doesn't change the fact that "=" would have been first choice for an
equality operator.
= for assignment and == for equality is fine if you never use anything else. But when you've got to switch between =, <-, := and == depending on the language you happen to be using, it ends up as a nuisance.
 
J

Joe keane

And there could be assemblers that don't *unambiguously* specify the
CPU instructions to be generated, though I've never used such a thing
myself.

A lot of machines don't really have a NOP instruction. The assembler is
free to pick whichever instruction it likes, that does nothing.
 
K

Keith Thompson

BartC said:
BGB said:
On 5/2/2012 8:16 AM, Rui Maciel wrote: [...]
yeah, I like = and == the way they are.
I wouldn't mind too much if the compiler give a warning (or even an error)
if '=' were used directly in an 'if' conditional.

but, then again, it isn't really a common error.

I do it all the time, when writing C code (which admittedly isn't that
often).

The two main compilers I use don't give a warning, not with the default
options anyway.

Using the default options is not necessarily a good idea.

I suggest finding out how to crank up the warning level for each
compiler you use, and perhaps set up an alias to pass those options
automatically.
 
K

Keith Thompson

BGB said:
Le 02/05/12 16:35, James Kuyper a écrit :
On 05/02/2012 08:40 AM, Jens Gustedt wrote:
Am 05/02/2012 08:02 AM, schrieb Ian Collins:

It can where the type can be deduced, the standard uses an example:

auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>

You mean the C++ states this, I suppose. Could you translate that into
something for C? int[2]?

std::initializer_list<> is a relatively new standard library template.
It's too new for me to be very familiar with it; I stopped paying close
attention to the C++ standard around the time they started preparing the
2003 standard. Key sections mentioning initializer lists seem to be
8.5.4,13.3.3.1.5, and 18.9. I've no idea whether the concept could or
should be adapted to C; I think that C might need to take a simpler
approach to the cases where C++ relies upon initializer lists.


Excuse me but how should that work?

auto foo = 45;

What should that be?

AFAIK, absent anything else, the default type here is 'int'.
char, short, int, long long, unsigned char, unsigned short, unsigned int
or unsigned long long?

it defaults to int, as there is little reason for anything smaller.
int is sort of the "implicit default type" in C (though it is at least a
little more explicit in C99, "implicit int" and similar tend to remain,
well, implicitly...).

long or long-long literals generally require suffixes, such as L or LL.
ALL those types qualify actually. Even float and double qualify also.

actually, no:
you only get float or double if it has a form like '1.0' or similar.

IIRC, in C it defaults to double in this case.
[...]

There's no ambiguity for simple cases like this; the type is the type of
the initializer expression:

auto x = 42; /* 42 is of type int */
auto y = 'y'; /* 'y' is of type char in C++, int in C */
auto z = 1.0; /* 1.0 is of type double */

In C++, the types of x, y, and z are int, char, and double,
respectively. In particular, x is of type int not because int is
the "default implicit type" in C, but because 42 is of type int.

If C adopted C++'s "auto" feature, they'd presumably be of types int,
int, and double, respectively (the type of a character constant is one
difference between C and C++.)

The C++ rules for auto are more complicated:

Once the type of a declarator-id has been determined according to
8.3, the type of the declared variable using the declarator-id is
determined from the type of its initializer using the rules for
template argument deduction.

and I don't claim to understand them.

Presumably a C version of this feature would be defined more simply,
while maintaining at least some compatibility with C++.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,082
Messages
2,570,589
Members
47,211
Latest member
Shamestone

Latest Threads

Top