Has thought been given given to a cleaned up C? Possibly called C+.

  • Thread starter Casey Hawthorne
  • Start date
P

Phil Carmody

Ben Bacarisse said:
That's too strong a criterion for me. A mnemonic can be a reminder of
some part (even a small part) of the whole. It does not have toi
substitute for understanding.

But it misleads. If you don't have prior understanding it may
inhibit the gaining of that understanding.
Exactly the "some mnemonic value" the Keith stated: it describes the
direction of the data flow. It does not describe anything else not
does it substitute for understanding the whole expression.

It seems to me an uncontentious claim, but then this is comp.lang.c
:) I won't argue this any further if you want to disagree for a last
time.

It's certainly not uncontentious. I've seen students who weren't
already familiar with C++ make incorrect assumptions due to the
visual mnemonic.

Phil
 
P

Phil Carmody

Ben Bacarisse said:
Not all such sets of matrices from a ring. I'm sure you know that.

I can't think of any off the top of my head on the assumption that
the matrix is defined over a ring, which is the standard definition
in abstract algebra. What am I overlooking? If you're escaping from
the field of abstract algebra, then you'd better start by defining
what you mean by a matrix, otherwise there's no intersection of our
universe of discourse.
Agreed. But conversely, the fact that you can restrict the operation
does not diminish the fact that, to some, the analogy with
multiplication is strained.

Discussions here would be so much more productive if people took the
time to acknowledge some validity (if there is some) in other people's
point of view. Pretty much the only reason I posted was that your
reply was so totally dismissive of Alan's view.

Where Alan's view was:
On what planet is that not dismissive of an entire disparate class
of people's views? Assuming there's a million mathematicians in the
world, I was a million times less dismissive than Alan when I replied.
I am with you in that
I see why mathematicians call it multiplication, but I can also see
the craziness -- the operation is not even defined for some pairs of
matrices. Your reply essentially said "it is called multiplication
because it is multiplication".

No, because it satisfies everything I and mathematicians demand
multiplication in a ring to do.

Phil
 
S

Seebs

Disagree.

I don't think a mnemonic has to help you remember everything, just one
particular thing. A mnemonic that helped me remember which stdio functions
are fFOO(fp, ...) and which are fFOO(..., fp) would be useful to me,
even if it didn't tell me what the specific functions do, or cover the
fact that you're supposed to seek between reading and writing from the
same stream.

If the "flow" mnemonic helps someone remember the semantics of an
individual (a >> b) or (a << b) operation, that's helpful, even if it
doesn't address the question of associativity.

-s
 
N

Neville Dempsey

Algol-68 never really arrived (at least I've never found a working version),
so it can't have gone anywhere.
Try: http://sourceforge.net/projects/algol68/files/ - Site includes:
* source for Algol68g (interpreter) and Algol68toC (translator)
- A68g is known to compile on Sun, HPUX, AIX, OSX and BSD...
* Binary installers for Windows, RHEL, Fedora, Ubuntu and Debian.
In that case it is an interesting abstract language to compare ideas with,
or as a model of how to implement, or not implement, a particular feature..

Actual Algol 68 *code* isn't that abstract, for examples check out and
compare with C code on:
* http://rosettacode.org/wiki/Category:ALGOL_68
(Hint: Try and contribute one example)

Also: "The Cambridge CAP Computer and Its Operating System"
* http://www.reddit.com/r/programming/comments/bbcoc/ancient_operating_system_written_in_algol68_with/
{No relation to Google Chrome OS, Android OS or Go :) }

Algol68 was more of a EU thing with (at least) three British OS -
DRA's Flex, ICL's VME and Cambridges CAP - written in Algol68
variants. And also one Soviet OS: Elbrus-1.

I believe that VME is still running - in production - as Linux/
Unixware guest VMs. The British and the Australian Custom services
almost certainly are still using VME in production. Maybe there are
even a few Soviet and British missile guidance systems were written in
Algol 68 and still in use?

Enjoy
NevilleDNZ
 
N

Neville Dempsey

Algol-68, of course, allowed you to define precedence as well...

Algol68 Operators can be overloaded, and so arguments are STRONG typed
and so no coercions occur. Procedures cannot be overloaded and so must
be unique, standard coercions apply. Both can take tagged-unions as
arguments... but tagged-unions are a bit awkward to use.

This duality all looks a bit like a "one language, two systems"
compromise.

Operators cannot be pointed at (no REF OP allowed), whereas REF PROC
is allowed.

*Dyadic* Operators can have their priories changed on a per scope
basis. This is not so useful (and confusing) for existing operators,
but very useful when defining new operator tokens... All operator
precedence is left associative.

The following are NOT operators: Array subscripting/slicing [],
procedure invocations (), coercions, pointer comparisons :=: (IS and
ISNT), implied pointer de-referencing and "new" ( from LOC/HEAP) are
not programmer re-definable and their precedence is unalterable.

Enjoy
NevilleDNZ
 
B

Ben Bacarisse

Phil Carmody said:
I can't think of any off the top of my head on the assumption that
the matrix is defined over a ring, which is the standard definition
in abstract algebra. What am I overlooking?

All the cases that support the contrary view. Of course there is
nothing peculiar about matrix multiplication if you limit your view to
those cases where it is not at all peculiar (square matrices over a
ring).
If you're escaping from
the field of abstract algebra, then you'd better start by defining
what you mean by a matrix, otherwise there's no intersection of our
universe of discourse.

I'd be prepared to bet that even your definition includes non-square
matrices.

There does appear to be very little useful discourse. I doubt anyone
else is reading this anymore and think we have both made our positions
clear so it's probably best to leave it as an unresolved disagreement.
Where Alan's view was:

On what planet is that not dismissive of an entire disparate class
of people's views?

I am a mathematician (at least by training) and did not feel my views
were being dismissed (despite being one of those who agree with you on
the reasonableness of calling it multiplication). In fact, I am not
even sure that is was meant as anything more than a throwaway humorous
remark. But one thing I am certain of is that on this point we will
not agree. This is best left as something else we agree to differ on.
Assuming there's a million mathematicians in the
world, I was a million times less dismissive than Alan when I replied.


No, because it satisfies everything I and mathematicians demand
multiplication in a ring to do.

Obviously so if you consider only those sets of matrices that form a
ring. I must be fair and highlight that this is exactly why your
argument is sound: matrix multiplication is reasonably named because of
the widely useful cases where it is unremarkable.

Your argument is unsound because it ignores the other cases where
matrix multiplication is either undefined or, at best, not closed; and
where attempting to close the set generates a structure that is not a
ring.

I don't think I can explain myself any better and, in anticipation of
your not agreeing with me, I will withdraw from this exchange. Please
don't take the absence of a reply as being anything other than a
feeling that I can't add anything more that could be useful.
 
P

Phil Carmody

Ben Bacarisse said:
All the cases that support the contrary view. Of course there is
nothing peculiar about matrix multiplication if you limit your view to
those cases where it is not at all peculiar (square matrices over a
ring).

I have explicitly limited myself to square matrices - see above. Your
response above explicitly says that not all such sets form a ring.
The followup, however didn't even begin to proffer an example, but
again insists there are such sets. If you're not over a ring, then
you can't add and scale matrices, which are operations I think everyone
should consider to have almost-intuitively obvious behaviour, and
you're on your own - you're not talking about the matrices anyone else
is, and you're almost certainly not talking about the matrix operation
that Alan Curry was complaining about.

Phil
 
R

Rod Pemberton

bartc said:
bartc said:
That's exactly what I was thinking, when I first looked at using C
around '92**. Surely someone would have got round to tidying up the
language by then?

Tidying up of C Language

[...]

Standard Headers

There are a dozen or two of these, and you have to keep including or
unincluding them as the contents of the file change.

Why not just take the inclusion of all of them as read? (There are
all sorts of reasons why it's kept like this, but remember a
newcomer to the language doesn't care about these reasons, only that
they are a right pain.)

There is much code that doesn't use them and has functions with identical
names, etc. E.g., I frequently need one or two string.h function(s). So, I
implement them with the same name and skip including string.h. You need
stdio.h for file I/O. But, who really needs ctype.h? stdlib.h? stdbool.h?
You can write equivalent code without them.
Type Qualifiers

Things such as long long unsigned int. This just looks silly (and I
know the idea came from Algol-68, I thought it silly there too).

Avoid qualifiers. IMO, they lead to more errors than they fix. Yup, "long
long" is the ""keyword"" with a space in it. It should've been "longlong"
or "llong". It creates problems with very simple C parsers.
Type Declarations

These are C's famous convoluted inside-out declarations. I've
already suggested a left-to-right alternative (which might just
co-exist with the old scheme)

It works. It allows the *creation* of _many_ types from a few very simple
syntax elements. I'm not sure I can say that about any of the other
languages I've experienced.
Numeric Literals

Who would have guessed that 0123 is an octal number? Get rid of that
notation, and introduce 8x123 if anyone is still interested.

You mean 0t123? (Think about it...) Yes, octal is not used much anymore.
But, when you need it. It's convenient.
And there should be a notation for binary literals, perhaps 2x11011.

Why? Learn hexadecimal. No joke. Each letter corresponds to 4-bits.
And those strange suffixes you sometimes see: LU, LLU and so on,
are they really necessary? Why can't the type of the constant be
automatic?

I don't like those either. But, how would you specify type for
non-variables, i.e., constants?
Sizeof Operator

This just gives the number of bytes in a type (or the type of an
expression). That's fine, but what about getting the number of
elements of an array? Ie. without bothering having to divide the
bytes in the entire array by the bytes in one element...

No need for sizeof().
Type Limits

These is where you start seeing names such as USHRT_MAX and
LLONG_MIN (all tacky abbreviations we are constantly told to avoid
as macros and typedefs), and where you start wondering, is there a
Better Way?

(Such as, perhaps, long.max or signed char'min, which together with
a set of standardised short type names would tidy things up
considerably.)

I don't have a problem with the type limits. I do have a problem with the
inability to construct larger integer sizes. Most microprocessor assembly
languages allow cascading of integer instructions which allow you to build
integers larger than the native supported size, e.g., 128-bits using four
32-bit registers or memory locations. C doesn't. You can construct larger
types from smaller types, but how do you use "++" to increment the _larger_
type? You can't.
And this point you might think: the format string is usually a
string literal, the compiler knows what types are being supplied to
printf() or whatever, so why bother having to specify each format in
such excruciating detail (since as as soon as a type changes, you
might have to revise hundreds of such formats)?

So why not let the compiler do the work? (I think I suggested %?
format once as an automatic format specifier)

I don't like these either. Where would the compiler get the type info?
Operators

A power operator is missing (I think because no-one can decide what
to use, since * is heavily involved with pointers).

Yes. I think we are all jealous of BASIC's ability to do exponentiation...
without using a function.
The << and >> operators have a strange precedence (they effectively
multiply and divide, so should be the same as * and /)

Never noticed an issue with this.
Switch Statement

It should not be necessary to use break to terminate every case
statement.

Whoa!!! Yes it should use a break. There is much code that uses
fall-through. The concepts of "status flags" and "fall-through" were all
the rage when "structured programming" concepts were taught. Let's say you
want to do something very common, like have a handful of non-sequential
integer values (and respective case labels) execute the same block of code
in the switch. Do you duplicate the code four times?

case 0x??:
break;
case 0x10:
case 0x33:
case 0x40:
case 0x41:
/* stuff */
break;
case 0x??:
break;
Case expressions should be able to use ranges and commas:

case 1,2,3,5..7,8:

I'm not fond of this PASCAL syntax. Although, it would simplify case
labels. Of course, once you've done this you might as well implement ranges
or sets too, like PASCAL.
And Switch statements are very strange in that the case statements
do not form a normal block scope, so that you can have a case label
buried deep inside an embedded if statement or a loop! This is just
too weird to have in a serious language.

You are aware that C has both a structured switch() and an unstructured
switch(), yes? The unstructured switch() doesn't use block scope. You
can't nest these. The case labels are interspersed into other code,
typically including other control structures.
Multi-level Breaks from Loops

This would save a *lot* of mucking about with code. Just *have*
them!

IMO, this is an indicator that your code is structured inefficiently.
Named Constants

Ie. what someone might expect when writing const int x=1000; x is
variable not an alias for 1000.

Then don't use qualifiers...
Given that const really means read-only, there is no proper way of
assigning a name to a literal, other than workarounds using #define
and enum, both with their own restrictions.

Don't use enum or bitfields in structs, esp. if you need code to work on old
or simple C compilers.
Text and Binary File Modes

No comments needed...

Binary only works well, IMO.


There are other things you didn't mention like "=" for assignment. All the
other operators with an equal in them are two chars. A single equal
(assignment) is hard to differentiate from a double equal (comparison) in
basic text editors. Perhaps, they should've used colon-equal ":=", as they
originally considered. Conflict between implicit int and typedef's (C99
resolved). Keyword needed to clarify grammar for usage of a typedef.

Believe it or not, I recently ran into *old* code that used "static",
"double", and "register", as variables...


Rod Pemberton
 
E

Eric Sosman

bartc said:
I'm not necessarily providing any fixes here, just pointing out areas
that might cause raised eyebrows:

Standard Headers

There are a dozen or two of these, and you have to keep including or
unincluding them as the contents of the file change.

Why not just take the inclusion of all of them as read? (There are
all sorts of reasons why it's kept like this, but remember a
newcomer to the language doesn't care about these reasons, only that
they are a right pain.)

Since C has only a few name spaces, automatic inclusion of
all the declarations in all the headers would make a large (and
growing) group of identifiers reserved. Observe, for example,
the care C99 took to avoid making `bool' a keyword, in deference
to existing code that already defined its own `bool'.
Type Qualifiers

Things such as long long unsigned int. This just looks silly (and I
know the idea came from Algol-68, I thought it silly there too).

I suspect you misunderstand what type qualifiers are. For
starters, your example of `long long unsigned int' has none at all.
Type Declarations

These are C's famous convoluted inside-out declarations. I've
already suggested a left-to-right alternative (which might just
co-exist with the old scheme)

All you've suggested is putting the declarations through a
food processor to chop them into bits and rearrange the fragments.
(Well, no: You've also suggested a batch of new keywords to make
declarations look more COBOL-like.) IMHO that doesn't make the
problems (such as they are) any harder or easier, just different.

Requiring *two* different styles of declaration just makes
reading declarations twice as hard as it is today, since the
reader needs to know two different sets of rules.
Struct Namespace

Just a cause of confusion. Just let a struct name be equivalent to
a typedef name.

Seems to me that having one declaration declare two type
names might increase confusion, not decrease it.
Numeric Literals

Who would have guessed that 0123 is an octal number? Get rid of that
notation, and introduce 8x123 if anyone is still interested.

When I first encountered C in the late 1970's, two things
immediately leapt out at me as syntactic traps: leading 0 for
octal, and the prohibition of white space between the name and
parameter list of a function-like macro. "There," said I to
myself, said I, "are two fruitful sources of error that will
plague C programmers for ever and ever Amen."

Boy, was I wrong! In the thirty-plus years of reading and
writing C that followed, I've seen (and committed) errors of
all kinds, but never, not even once, have I been tripped up or
seen anyone else tripped up by either of these two fatal flaws.

Well, leading-zero-for-octal *has* caused trouble a couple of
times, when programmers have unwisely used "%i" or strtol(...,0)
to parse input from people unaware of the leading-zero convention.
The programmers have unwisely expected non-programmers to be
familiar with the programming language, and trouble has ensued.
But that's a problem not unique to the leading-zero matter; you
see the same sort of thing in

char *string = ...something the user enters...
printf (string);

.... when the user innocently enters "10%sales tax".
And there should be a notation for binary literals, perhaps 2x11011.

(Shrug.) I find it easier to read a more compact notation.
Quickly, now: is the 4096's bit set or clear in

2x11011110101011011011111011101111

? If the number were written as 0xDEADBEEF would you reach your
answer more or less rapidly?
And those strange suffixes you sometimes see: LU, LLU and so on,
are they really necessary? Why can't the type of the constant be
automatic?

It is. The suffixes are for when you need to override the
automatic choice.
Sizeof Operator

This just gives the number of bytes in a type (or the type of an
expression). That's fine, but what about getting the number of
elements of an array? Ie. without bothering having to divide the
bytes in the entire array by the bytes in one element...

Not sure what you mean here. If you've got an actual array
and want the element count, the division is a simple and reliable
way to get the answer. Wrap it in a macro if you like; I've done
so sometimes myself.

But if you're looking for a way to get the element count from
a pointer to an array element, or even to the [0] element, that's
a completely different can of worms, wriggly wriggly worms.
Type Limits
[... he wants to change the names, nothing more ...]
Format String Codes

These seem innocuous enough at first, sucgh as %d and %f. Then you
start to see %lu, %lld, %zu (or whatever), etc. etc.

(Strange how this long/long long business seems to be all-
pervading.)

C has a lot of types. You dislike this? Rather just get
along with unaided `int', perhaps?
And this point you might think: the format string is usually a
string literal, the compiler knows what types are being supplied to
printf() or whatever, so why bother having to specify each format in
such excruciating detail (since as as soon as a type changes, you
might have to revise hundreds of such formats)?

So why not let the compiler do the work? (I think I suggested %?
format once as an automatic format specifier)

As far as I can see, real true actual magic would be needed
(since C objects aren't required to carry their types around at
run-time in a form the program could query). Maybe Dumbledore C
could do it.
Switch Statement

It should not be necessary to use break to terminate every case
statement. (And there's the problem that break cannot then be used
to escape from a loop).

Okay, as long as you leave me a way to get fall-through when
I want it. As for loop escape, there are some "creative" things
one can do by (ab)using `continue'.
For Statement

This is a funny, but useful, variation, of a loop statement, but is
not a For statement as normally understood. A streamlined 'proper'
For statement would be handy (but is awkward to fit into C's zero-
based philosophy).

Your objection is unclear to me.
Text and Binary File Modes

No comments needed...

Your objection is unclear to me.
Compiler Attributes

When you look at actual header files they always seem to be full of
cr*p like this (and often a lot worse):

_CRTIMP __p_sig_fn_t __cdecl __MINGW_NOTHROW signal(int, __p_sig_fn_t);

all full of ad-hoc non-portable extensions specially designed to
make declarations completely incomprehensible.

Whatever it is these attributes are supposed to do, why not just
standardise them?

Because they're the implementation's own province, not yours.
Do you intend to forbid an implementation from doing non-portable
things? You'll have a hard time doing I/O -- heck, you'll have a
hard time getting your own main() called.
Well, that's about all I could think of before breakfast.

Sorry to hear about your upset stomach.
 
W

William Hughes

On Mar 13, 10:35 am, Phil Carmody

. If you're not over a ring, then
you can't add and scale matrices,


Nope. Consider the set of all finite
matrices over the reals
(my preferred definition is in terms of linear
transformations from one finite vector space to another,
but there are many others,). There are no obvious
operations to make this
into a ring. However, you can scale any matrix in
this set, including non-square matrices. (And you can
add any two matrices of the same size, including
non-square matrices. Characterizing this as "you
can't add matrices" is silly)

I do not think that your thesis,

matrix multiplication is called multiplication
because it is a generalization of the "multiplication"
operation used in rings that are formed by subsets
of the set of all finite matrices,

holds water. My alternate thesis is:

matrix multiplication is called multiplication
because it corresponds to composition, an operation
that is often represented as multiplication.

A quick search has not turned up anything
for or against either thesis.

- William Hughes
 
B

Ben Bacarisse

Eric Sosman said:
On 3/10/2010 9:14 AM, bartc wrote:

(Shrug.) I find it easier to read a more compact notation.
Quickly, now: is the 4096's bit set or clear in

2x11011110101011011011111011101111

? If the number were written as 0xDEADBEEF would you reach your
answer more or less rapidly?

On this particular point, some languages permit a separator. I think

2x1101,1110,1010,1101,1011,1110,1110,1111

ticks both boxes, though it is even less compact. I don't think ',' is
necessarily the best choice -- I just grabbed an example character.

<snip>
 
E

Ersek, Laszlo

What is the advantage of having both? AFAIK they have the same
semantics and the same computational complexity.

Wikipedia says in <http://en.wikipedia.org/wiki/AVL_tree>:

----v----
AVL trees are often compared with red-black trees because they support
the same set of operations and because red-black trees also take
O(log n) time for the basic operations. AVL trees perform better than
red-black trees for lookup-intensive applications.[3]
----^----

Footnote [3] links to "Performance Analysis of BSTs in System Software",
authored by Ben Pfaff, incidentally.

lacos
 
E

Ersek, Laszlo

Matrix multiplication is not "just crazy" it
corresponds to composition of linear
transforms. The operation of taking two operators
and forming a third by composition is frequently
called multiplication.

Furthermore, for 1x1 matrices, matrix multiplication coincides with
scalar multiplication. Matrix multiplication is associative, and
distributive over matrix addition. It is related to the scalar product.
The "determinant is a multiplicative map".

http://en.wikipedia.org/wiki/Matrix_multiplication
http://en.wikipedia.org/wiki/Determinant

lacos
 
B

bartc

Since C has only a few name spaces, automatic inclusion of
all the declarations in all the headers would make a large (and
growing) group of identifiers reserved. Observe, for example,
the care C99 took to avoid making `bool' a keyword, in deference
to existing code that already defined its own `bool'.

I think I combined all the headers once, and the resulting file was still
small, at least compared to say windows.h. And on a typical development
machine, that shouldn't be an issue.

As to avoiding clashes with user-space, my other comment about having
'proper' headers instead of simple include files, might have helped here by
having system names in a higher scope that could be overridden by user
identifiers.

Otherwise, in the case of using bool: surely there are tools that will
refactor code so that problem names (that are now keywords for example) are
fixed, by substituting an automatic or user-supplied alternative (or by
using the C# idea of using @name I think it was, to allow @name as an
identifier, when name is a reserved word.)
I suspect you misunderstand what type qualifiers are. For
starters, your example of `long long unsigned int' has none at all.

Well, I defined what I meant by it. long long unsigned int (even with the
small redundancy removed) is still a mouthful. And makes for longer
declarations that are different to grasp in a glance.
All you've suggested is putting the declarations through a
food processor to chop them into bits and rearrange the fragments.

Yes, rearranged so they are instantly readable without having to enlist
the help of CDECL, or following an algorithm.
Requiring *two* different styles of declaration just makes
reading declarations twice as hard as it is today, since the
reader needs to know two different sets of rules.

C already allows these two styles: however the left-to-right type-spec that
I'm suggesting might go at the start of a declaration, has to be built up
first using typedef, and needs a name assigned to it. This seems a
recommended method of building complex types.

I'm saying this can be done without bothering with creating a new, named
type using typedef.
When I first encountered C in the late 1970's, two things
immediately leapt out at me as syntactic traps: leading 0 for
octal, and the prohibition of white space between the name and
parameter list of a function-like macro. "There," said I to
myself, said I, "are two fruitful sources of error that will
plague C programmers for ever and ever Amen."

Boy, was I wrong! In the thirty-plus years of reading and
writing C that followed, I've seen (and committed) errors of
all kinds, but never, not even once, have I been tripped up or
seen anyone else tripped up by either of these two fatal flaws.

If I'd used C that long (rather than sporadically for a few years), then I'm
sure it would have tripped *me* up: sometimes I like lining up tables of
numbers, and sometimes I like to space those numbers using leading zeros...
(Shrug.) I find it easier to read a more compact notation.
Quickly, now: is the 4096's bit set or clear in

2x11011110101011011011111011101111

You mean bit 11? I would also introduce separators between digits (I use
these elsewhere), your example might then look like:
2x1101_1110_1010_1101_1011_1110_1110_1111

Then bit 11 would be 1.
? If the number were written as 0xDEADBEEF would you reach your
answer more or less rapidly?

In an old thread on this, I gave an example of a literal that had to consist
of, starting from the lsb, one 1 bit, two 0 bits, three 1 bits, four 0 bits,
five 1 bits, six 0 bits, and seven 1 bits. In binary that would be:

2x1111111000000111110000111001

or, misusing my separators:

2x1111111_000000_11111_0000_111_00_1

How does that look in hex? And without writing in binary first...

No, binary literals would have been really trivial to implement in the early
days of C, and would have been very handy.
Not sure what you mean here. If you've got an actual array
and want the element count, the division is a simple and reliable
way to get the answer. Wrap it in a macro if you like; I've done
so sometimes myself.

Sure, like lengthof(). Or length(). Or dim(). Or array_length(). Or
whatever. Which then is put into your personal headers, so that when you
post code here for example, it will cause problems.

If it was part of the language, then it'd be standardised.
But if you're looking for a way to get the element count from
a pointer to an array element, or even to the [0] element, that's
a completely different can of worms, wriggly wriggly worms.

I'm not looking at significant language extensions here.
As far as I can see, real true actual magic would be needed
(since C objects aren't required to carry their types around at
run-time in a form the program could query). Maybe Dumbledore C
could do it.

In this example, using my suggestion of "%?":

int a;
double b;
char *c;

printf ("A,B,C = %? %? %?",a,b,c);

The compiler knows the format string, and can change those "%? %? %?" to "%d
%f %s".

In the rarer case of using a runtime format, let's say containing "A,B,C =
%? %f %s", then yes it's a little more difficult:

char *fmt;

printf (fmt, a,b,c);

There are a number of ways to tackle this without having to write any
special code. For example, for the compiler to transparently convert to:

qprintf(fmt,'d',a, 'f',b, 's',c)

Ie. calling a variation of printf() where every parameter is preceded by
it's main format character. If a format code is "?", it will use the one
supplied; if not, it will ignore the supplied code.

However this is less efficient when most format strings will be
conventional. Possibly better then to explicitly can the special printf
version that adds those extra codes (and the compiler needs to be aware
of these special functions).
Your objection is unclear to me.

It's been discussed here before. In my reply to Keith, I gave an example of
a short, sweet variation on 'for'.
Your objection is unclear to me.

Possibly on your OS, text and binary modes are the same. In mine, text mode
always seems to give problems.
Because they're the implementation's own province, not yours.
Do you intend to forbid an implementation from doing non-portable
things? You'll have a hard time doing I/O -- heck, you'll have a
hard time getting your own main() called.

Either these headers are supposed to be human-readable, or not. Sometimes I
have to try and decipher these things as I try and call some API or other
from a non-C language, and the only details provided are in a C header file.

If these attributes are to do with calling conventions, then there aren't
too many of those, and perhaps they can just be listed somewhere.
 
B

bartc

There is much code that doesn't use them and has functions with
identical names, etc. E.g., I frequently need one or two string.h
function(s). So, I implement them with the same name and skip
including string.h. You need stdio.h for file I/O. But, who really
needs ctype.h? stdlib.h? stdbool.h? You can write equivalent code
without them.

In the context of this thread (a new, cleaned up C), then it might be time
to tidy up those bad habits! Either a name is built-in to C, or not.

But with the other idea of using a header file in it's own scope (see my
reply to Eric), you can override the built-in name.
It works. It allows the *creation* of _many_ types from a few very
simple syntax elements. I'm not sure I can say that about any of the
other languages I've experienced.

It works, but badly, because quite a few people have problems with them.
Why? Learn hexadecimal. No joke. Each letter corresponds to 4-bits.

See my reply to Eric. Some bit-patterns are akward to translate to hex. And
even when not, there is scope for error.
I don't have a problem with the type limits. I do have a problem
with the inability to construct larger integer sizes. Most
microprocessor assembly languages allow cascading of integer
instructions which allow you to build integers larger than the native
supported size, e.g., 128-bits using four 32-bit registers or memory
locations. C doesn't. You can construct larger types from smaller
types, but how do you use "++" to increment the _larger_ type? You
can't.

I think that has been discussed in this thread too. See any posts by Jacob
Navia.

[Format strings]
I don't like these either. Where would the compiler get the type
info?

The compiler? The compiler knows everything! At least, mine warns me when I
use the wrong format specifier, so presumably it must know which is the
right one.
Whoa!!! Yes it should use a break. There is much code that uses
fall-through.

I would guess that break is used somewhere between 90% and 100% of the time.

But obviously this would be tricky to change overnight (like changing
between driving on the right, and driving on the left). It doesn't change
the fact that not needing the break would be better.
The concepts of "status flags" and "fall-through" were
all the rage when "structured programming" concepts were taught.
Let's say you want to do something very common, like have a handful
of non-sequential integer values (and respective case labels) execute
the same block of code in the switch. Do you duplicate the code four
times?

case 0x??:
break;
case 0x10:
case 0x33:
case 0x40:
case 0x41:
/* stuff */
break;
case 0x??:
break;

I don't quite get this. You mean whether or not those empty case statements
above would each have a break rather than falling through?

I've never thought of it like that. However, with the following suggestion,
those cases would all be properly grouped together, and the problem doesn't
occur...
I'm not fond of this PASCAL syntax. Although, it would simplify case
labels. Of course, once you've done this you might as well implement
ranges or sets too, like PASCAL.

No, my post is merely about things that might cause 'raised eyebrows',
rather than redesigning the language (I design my own languages anyway, so I
can let off steam with those...)

And code such as: case 1: case 2: case 3: ... case 100: I think would have
such an effect.
You are aware that C has both a structured switch() and an
unstructured switch(), yes? The unstructured switch() doesn't use
block scope. You can't nest these. The case labels are interspersed
into other code, typically including other control structures.

Are you sure? The following seems to nest (and prints TRUE):

int a,b,c;

a=13;

switch(a)
case 9: case 10: case 11:
if (0)
case 13:
puts("TRUE");

IMO, this is an indicator that your code is structured inefficiently.

Possibly. But until I get round to structuring properly, these breaks are
handy to have.

(Or maybe it will never get structured, since the program is run once and
that's it, or it's code in development which keeps changing and the break
disappears at some point, or I just don't care...)

The workarounds for multi-level breaks can mean turning code upside down,
and I'd rather not do that until I'm ready.
There are other things you didn't mention like "=" for assignment.
All the other operators with an equal in them are two chars. A
single equal (assignment) is hard to differentiate from a double
equal (comparison) in basic text editors. Perhaps, they should've
used colon-equal ":=", as they originally considered.

I doubt that would have been a popular suggestion in a C language group. Use
of = and == is too widespread now to change in those languages.
 
K

Keith Thompson

Rod Pemberton said:
There is much code that doesn't use them and has functions with identical
names, etc. E.g., I frequently need one or two string.h function(s). So, I
implement them with the same name and skip including string.h. You need
stdio.h for file I/O. But, who really needs ctype.h? stdlib.h? stdbool.h?
You can write equivalent code without them.

Why on Earth would you do that? Is there something wrong with using
the standard library?
Avoid qualifiers. IMO, they lead to more errors than they fix. Yup, "long
long" is the ""keyword"" with a space in it. It should've been "longlong"
or "llong". It creates problems with very simple C parsers.

"long long" doesn't cause any particular problems for non-buggy C
parsers. Typedefs on the other hand, do cause problems.

[...]
Sizeof Operator

This just gives the number of bytes in a type (or the type of an
expression). That's fine, but what about getting the number of
elements of an array? Ie. without bothering having to divide the
bytes in the entire array by the bytes in one element...

No need for sizeof().
What?

[...]
Switch Statement

It should not be necessary to use break to terminate every case
statement.

Whoa!!! Yes it should use a break. There is much code that uses
fall-through. The concepts of "status flags" and "fall-through" were all
the rage when "structured programming" concepts were taught. Let's say you
want to do something very common, like have a handful of non-sequential
integer values (and respective case labels) execute the same block of code
in the switch. Do you duplicate the code four times?

case 0x??:
break;
case 0x10:
case 0x33:
case 0x40:
case 0x41:
/* stuff */
break;
case 0x??:
break;

Fallthrough from a non-empty case is relatively rare. If I were
redesigning the switch statement from scratch, you'd be able to
specify multiple values in a single case, the "break" keyword
would not be required, and there would probably be special syntax
to specify falling through to the next case.

On the other hand, I'm not 100% sure I'd even want to support
fallthrough from one case to the next; it's a bit of a hack, and
it makes the code difficult to maintain.

[...]
Then don't use qualifiers...

How does that address the issue? If you drop the "const", x still
isn't an alias for 1000.
Don't use enum or bitfields in structs, esp. if you need code to work on old
or simple C compilers.

What? The enum feature has existed in its current form since before
K&R. Bit fields don't guarantee any particular layout, but their
semantics are well defined.
Binary only works well, IMO.

Unless you need to handle text, of course. And no, manually handling
the '\r' and '\n' characters is not a good solution, especially if
your code might ever be ported to a system with a different text file
format.

[...]
Believe it or not, I recently ran into *old* code that used "static",
"double", and "register", as variables...

How old was it? "static", "double", and "register"
have been keywords in C for a *very* long time; see
<http://cm.bell-labs.com/cm/cs/who/dmr/cman.pdf>.
Could the old code have been written in B rather than C?
 
K

Keith Thompson

Ben Bacarisse said:
On this particular point, some languages permit a separator. I think

2x1101,1110,1010,1101,1011,1110,1110,1111

ticks both boxes, though it is even less compact. I don't think ',' is
necessarily the best choice -- I just grabbed an example character.

No, ',' is not the best choice, since
2x1101,1110,1010,1101,1011,1110,1110,1111 is already a valid
expression (or it would be if 2x1101 were permitted).

There's ample precedent in other languages (Ada, Perl, etc.) for
allowing '_' in numeric literals:

2x1101_1110_1010_1101_1011_1110_1110_1111

And speaking of precedent, I've seen "0b1101" used for binary
constants. "2x..." makes sense, but it mildly clashes with "0x..."
for hexadecimal. If I were redesigning the language from scratch,
I might use "2x...", "8x...", and "16x..." (no need to support
other bases). If compatibility with current C is an issue (and it
certainly is!), I'd go with "0b...", "0...", and "0x...".
 
J

Jasen Betts

Jasen Betts a écrit :

Yes. If you look at the header files,

where are they found?

--- news://freenews.netfront.net/ - complaints: (e-mail address removed) ---
 
K

Keith Thompson

bartc said:
Eric said:
On 3/10/2010 9:14 AM, bartc wrote: [...]
Type Qualifiers

Things such as long long unsigned int. This just looks silly (and I
know the idea came from Algol-68, I thought it silly there too).

I suspect you misunderstand what type qualifiers are. For
starters, your example of `long long unsigned int' has none at all.

Well, I defined what I meant by it. long long unsigned int (even with the
small redundancy removed) is still a mouthful. And makes for longer
declarations that are different to grasp in a glance.

Those are type specifiers. The type qualifiers are "const",
"restrict", and "volatile".

[...]
 
E

Eric Sosman

[...]
Otherwise, in the case of using bool: surely there are tools that will
refactor code so that problem names (that are now keywords for example) are
fixed, by substituting an automatic or user-supplied alternative (or by
using the C# idea of using @name I think it was, to allow @name as an
identifier, when name is a reserved word.)

"Existing code is important, existing implementation are not."
-- Rationale

Do you have any idea of the sheer volume of C source code that's
out there? I don't: All I can say is that it's in excess of a
hundred million lines -- I know of one single product suite that
comes to a quarter that amount all by itself. So, try this thought
experiment: Imagine yourself trying to tell someone that he's got
to take all that code and run it through an untested (unwritten!)
tool and cope with the inevitable glitches. (Success rate of
99.99% means more than a hundred thousand problems.) Is it more
likely that you'll persuade the owner of the code to spend money
fixing a hundred thousand brand-new bugs, or that you'll be thrown
out on your ear?
Well, I defined what I meant by it. long long unsigned int (even with the
small redundancy removed) is still a mouthful. And makes for longer
declarations that are different to grasp in a glance.

First, you offered no definition at all. Second, when you
use a word or phrase already defined by the Standard to mean
something other than the Standard means, it's as well to state
explicitly that you're not using agreed-upon terminology.
In this example, using my suggestion of "%?":

int a;
double b;
char *c;

printf ("A,B,C = %? %? %?",a,b,c);

The compiler knows the format string, and can change those "%? %? %?" to
"%d
%f %s".

Sorry; you lost me there. How can the compiler know that
`c' points to the start of a string, rather than to a single
one-off isolated `char' object? That is, how does the compiler
know whether "%s" or "%c" or "%d" (or "%u") is appropriate?
Possibly on your OS, text and binary modes are the same. In mine, text mode
always seems to give problems.

You've got it backwards. C streams have text and binary
modes for the benefit of systems where they *aren't* the same.
It is not C's business to legislate the file formats used by
its host platforms.
Either these headers are supposed to be human-readable, or not.

Right. The latter. End of discussion.
 

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

Forum statistics

Threads
474,123
Messages
2,570,741
Members
47,296
Latest member
EarnestSme

Latest Threads

Top