If you could change the C or C++ or Java syntax, what would you like different?

J

Jon

Seebs said:
Only it isn't. It's more consistent with the standard than yours.


And you haven't now, either, because that's not what I said.

You tell him Seebs.
So far as I'm concerned, size_t really is a distinct type from
any other integer type.

Damn it! And you were doing so good for a second. No worries, "I" still
hate you.
As it happens, it is quite likely that the
compiler can't tell it from other integer types,

Seebs is a.... ??? (programmer or language lawyer? Stay tuned folks,
TBD!!).
but that doesn't
mean that it's not a different type, just that C isn't very good
at telling types apart.

A language lawyer wannabe?
I would view this precisely the other way. You are welcome to
declare that two types the compiler is not smart enough to distinguish
are not in fact distinct types, but I find it more useful to remember
that they may well be distinct types anyway, and avoid mixing them
up.

What is a "type"?
 
J

Jon

Joshua said:
You want something which your language does not give you. It's not "C
is bad at telling types apart", it's "typedef does not define new
types". You cannot fiat the terms to mean whatever you want.

I "once" "wanted" an MG. Time, and therefore age, matters (or is it the
other way around?). What matters? Does anything matter?
 
J

Jon

Seebs said:
No, I'm fine with what it gives me.

What does it give you?
It defines new type-names,

Nope. Can't have a discussion if ya keep changin up the avenue. Hmm?
though, and the best available
programming practice is to treat them *as though* they are new
types.

Pfft. (*Not* a "phooey").

("weasel words")
that in some cases you can get away without
doing that doesn't mean that it's ever a good idea.

Take your pills now. This is your reminder msg to take your pills now. I
am just kidding, this should not be taken seriously as a reminder to take
pills of any kind. Nor is it suggesting that you don't take your pills.
This post and you and your pills are all orthogonal. This post is not
meant to confuse. No warranty of merchantability or fitness for a
particular purpose should be assumed, for none is given.

(Is it Friday yet?).
 
I

Ike Naar

I would view this precisely the other way. You are welcome to
declare that two types the compiler is not smart enough to distinguish
are not in fact distinct types, but I find it more useful to remember
that they may well be distinct types anyway, and avoid mixing them
up.

We are talking about different notions of type equivalence.
To avoid confusion, it might be a good idea to label them as such.
For now we might call them C-equivalence (C treats them as equivalent,
that is, a C compiler cannot distinguish them),
and S-equivalence (Seebs treats them as equivalent).

struct a { int x; }
struct b { int x; }
typedef struct a ta;
typedef struct b tb;

``struct a'' and ``struct b'' are obviously C-distinct
(that is, not C-equivalent), and most probably also S-distinct.
``ta'' and ``tb'' ditto.
``struct a'' and ``ta'' are C-equivalent, but they can be S-distinct.

My conjecture is that S-equivalence is stronger than C-equivalence
(that is, S-equivalence implies C-equivalence).

I'm not sure whether there exist types that are S-equivalent, if so,
Seebs is welcome to show an example. In that case, it would be nice
to know if there are objective criteria to determine whether two
given types are S-equivalent (C-equivalence being a necessary, but
not sufficient condition).
 
R

Rui Maciel

Jon said:
I was just rephrasing what you said. So you are saying that *you* are
wrong.

If your intention was to rephrase what I had said then you should have preserved the message.
Instead, you botched it and, unintentionally or not, you put out a strawman.


Rui Maciel
 
R

Rui Maciel

Jon said:
Many of us have been for decades fixing up the shortcomings via a number
of ways (not to mention idoms, processes, libraries, any yes, macros) and
are taking the next obvious step. So, soon new programmers won't have to
learn archaic languages (unless they want to be historians?).

You may make all the appeals to authority that you wish but in this branch of the discussion alone
(i.e., the typedef issue) it was already demonstrated that there is absolutely no problem with the
language, only with a poor understanding of it. You don't fix ignorance by creating a completely
new programming language that must be learned from scratch.

Read what you wrote just above and you tell me what's silly about what
you said. (Hint: types, what are they?).

As I've pointed out, your attempt at rephrasing what I said ended up being a poorly made strawman.
So please take the time to read what I wrote and feel free to go back and correct your statement.


Rui Maciel
 
K

Keith Thompson

Seebs said:
And one of the core weaknesses of C is that it has always had a real
problem in that it tends to have types which are interchangeable
despite being officially distinct.
[...]

And it also has types that are *not* interchangeable despite being
otherwise identical, such as (depending on the implementation)
signed char and char, int and long, unsigned long and size_t.

It's important to know which types are really distinct and which
are distinct only on a higher level of abstraction but identical
(i.e., the same type) on the language level.

And that's why it's important to keep in mind that, assuming int
and long have the same representation, and given
typedef int word;
int and long are distinct in a way that int and word are not.

There are declarations that do create new types, and they do
something that typedef does not. Saying that typedef creates a
"new type" makes it difficult to discuss that important distinction.
 
S

Seebs

I'm not sure whether there exist types that are S-equivalent, if so,
Seebs is welcome to show an example. In that case, it would be nice
to know if there are objective criteria to determine whether two
given types are S-equivalent (C-equivalence being a necessary, but
not sufficient condition).

"signed int", "int".

I think that and equivalent things are about it. I might actually also
agree to things like, say, "uint32" and "u_int32_t" or whatever, where it's
clear that both are intending to denote the same thing.

-s
 
T

Tim Rentsch

Jon said:
Tim said:
Joshua Maurice said:
[snip]

The usage of the term "define a type" in the programming world at
large, and in the C community, means "to define a /new/ type" or
"introduce a /new/ type". Specifically, the just-introduced type must
be distinct from all other types (in that translation unit) -
[snip elaboration]

This statement may be true of some parts of the C community, but
certainly it is not true for all.

Oh phooey on you: he said "in the large", not *all*. [snip]

If you read the quoted passage again you will see that what was
said was not "in the large", nor "in large part", nor "by and
large", but "at large". The term "at large" does not mean
"generally" but something more along the lines of "considered as a
whole". Moreover, the specific comment about C was not so
qualified. The statement is not true of the entire C community,
but more to the point it is not true of the C community generally.
I expect it is true for /some parts/ of the C community, but it
is not true for other (significant) parts of the C community.

That reasoning is incorrect (though I don't know your intentions).

No reasoning was presented, simply a statement, but apparently one
that needs clarifying. The thesis "the usage of the term 'define
a type' means 'to define a /new/ type' or 'introduce a /new/
type'" is not true of the programming world considered as a whole,
not even true just generally speaking. I'm sure it is true for
some parts of the programming world; for other (significant)
parts it is not. And the endurance of spirited debate in this
thread demonstrates this assessment to be so.
 
T

Tim Rentsch

Seebs said:
"signed int", "int".

Hey Mr C expert, did you forget about bitfields? :)

(intended in all friendliness to a generally acknowledged
clc "guru-in-residence"...)
 
S

Seebs

Seebs said:
And one of the core weaknesses of C is that it has always had a real
problem in that it tends to have types which are interchangeable
despite being officially distinct. [...]

And it also has types that are *not* interchangeable despite being
otherwise identical, such as (depending on the implementation)
signed char and char, int and long, unsigned long and size_t.
Yes.

It's important to know which types are really distinct and which
are distinct only on a higher level of abstraction but identical
(i.e., the same type) on the language level.

I'm not sure of this. Here's my question, I guess: Imagine that we
were to program in a hypothetical language to be called "C!". And C!
is precisely identical to C, except that typedefs are always viewed
as incompatible with any other type.

What would we really have to change in our programs? I wouldn't change
much of anything. I don't think that language would be worse than C,
or even substantially different in terms of actual code I write or much
of the code I've read. In fact, the only cases I can think of where code
would be invalid in "C!" would be cases where the code was wrong in C,
but the compiler couldn't tell. (Counting only real code, not examples
intended to illustrate aspects of the type system.)
There are declarations that do create new types, and they do
something that typedef does not. Saying that typedef creates a
"new type" makes it difficult to discuss that important distinction.

Hmm. I see your point.

I guess, in the context of that distinction, I'd say typedef defines a type,
but doesn't create one. Elsewhere, I'd just say it defines a type, and not
address the create/not-create distinction.

-s
 
S

Seebs

Hey Mr C expert, did you forget about bitfields? :)

Yup.

Total times I have used bitfields since I started programming in C: 0.

No, really. I've just plain never had a reason to, that I know of.

-s
 
K

Keith Thompson

Seebs said:
Only it isn't. It's more consistent with the standard than yours.


And you haven't now, either, because that's not what I said.

So far as I'm concerned, size_t really is a distinct type from
any other integer type. As it happens, it is quite likely that the
compiler can't tell it from other integer types, but that doesn't
mean that it's not a different type, just that C isn't very good
at telling types apart.

Types are defined by the language.

These things you're talking about, of which size_t is one example
and unsigned long is a distinct example, are very useful concepts.
But calling them "types" while discussing C just leads to confusion.
It's like calling 8-bit quantities "bytes" and insisting that an
implementation with CHAR_BIT==32 has 4-byte characters.

You are using a term, "type", that has a well-defined meaning in C,
and applying it to a closely related but very distinct concept.

Let's call these things "ltypes", short for "logical types" (the
name is not meant to imply that an ltype is a kind of type).

Assuming that the implementation has "typedef unsigned long size_t;".
Then unsigned long and size_t are the same type, but they are
distinct ltypes. A working C implementation is perfectly good
at telling types apart; it's just not very good at telling ltypes
apart (because ltypes aren't part of the language and it's not the
compiler's job to deal with them).

A sufficiently clever and friendly compiler might make some effort
to recognize ltypes and issue optional warnings when distinct ltypes
are mixed. A conforming compiler *must* issue a diagnostic when
distinct types are mixed in certain ways.

[...]
Down the path of insisting that there are no new types, we find
code which determines which integer type size_t is, then uses that
integer type interchangeably with size_t throughout thousands of
lines of declarations and code, and which blows up nicely when
ported.

Only if "no new types" is the only thing one understands. Code can
be correct for a particular implementation, but still horribly
non-portable. Keeping ltypes straight is one of many tools that
help keep your code portable.

I agree completely that it's important to keep in mind that size_t
and unsigned long are logically distinct. I just think it's equally
important to understand that they may or may not be distinct on
the language level.
 
K

Keith Thompson

This is exactly how things like size_t, off_t, uintXX_t etc are supposed
to work. If you care what they might be an alias for, you're doing it
wrong.

Agreed.

But if you don't care that they're aliases for *something*, then your
missing part of the picture.
 
S

Seebs

These things you're talking about, of which size_t is one example
and unsigned long is a distinct example, are very useful concepts.
But calling them "types" while discussing C just leads to confusion.

I don't think so.

7.17 Common definitions <stddef.h>

The following types and macros are defined in the standard
header <stddef.h>. Some are also defined in other headers,
as noted in their respective subclauses.

The types are
ptrdiff_t
which is the signed integer type of the result of subtracting two
pointers;
size_t
which is the unsigned integer type of the result of the sizeof
operator; and
wchar_t
which is an integer type whose range of values [...]

They're types.
You are using a term, "type", that has a well-defined meaning in C,
and applying it to a closely related but very distinct concept.

I'm calling size_t a type because the standard says it's a type.
A sufficiently clever and friendly compiler might make some effort
to recognize ltypes and issue optional warnings when distinct ltypes
are mixed. A conforming compiler *must* issue a diagnostic when
distinct types are mixed in certain ways.

Right. And that's the thing. You're assuming that types are inherently
distinct, but they're not in C. There are pairs of types which are not
distinct, but they're still both types.
I agree completely that it's important to keep in mind that size_t
and unsigned long are logically distinct. I just think it's equally
important to understand that they may or may not be distinct on
the language level.

On this, we agree.

I prefer to express it as "some types are not distinct", you prefer to
express it as "they may be of the same type". I think that the former
maps better onto the standard's language for types, typedef, and so on.

Consider the discussion of <stdint.h>. It "declares sets of integer
types." Interestingly, <stdint.h> is described as declaring these types,
while <stddef.h> was described as defining them.

Oh, man. Look at this one:

7.18, paragraph 4:

For each type described herein that the implementation provides,
<stdint.h> shall declare that typedef name and define the associated
macros. [...]

And then later, in 7.18.1.4:

The following type designates an unsigned integer type with
the property that...

Throughout 7.18, the standard appears to use "type" and "typedef name"
essentially interchangeably. 7.18.1.2 says "the typedef name
int_leastN_t", 7.18.4.1 refers to "corresponding to the type int_leastN_t".

I have a proposed statement that I think we can probably all agree on:

"The language in the standard to do with types, and whether it is types or
type names that are defined, or perhaps declared, does not achieve total
consistency and transparency."

It seems to me that the standard is pretty consistent in treating "type"
and "typedef name" essentially interchangeably, with "type X" clearly being
used as a shorthand for "the type designated by the typedef name X".

I am not sure whether this means I'm right, or only that my confusion is
shared by others.

-s
 
S

Seebs

But if you don't care that they're aliases for *something*, then your
missing part of the picture.

Am I?

I am not aware of anything prohibiting an implementation from having,
e.g., a size_t which does not correspond to ANY type you can declare by
ANY other means. At which point, it's only an alias for __internal_uint48_t
or whatever... and it's functionally completely distinct.

It's pretty common that the standard typedefs all correspond to SOMETHING
you could declare with some combination of the base keywords, but it doesn't
seem to me that it's required. We even have special language allowing for
"extended signed integer types" and "extended unsigned integer types".

-s
 
S

Seebs

It's important to know which types are really distinct and which
are distinct only on a higher level of abstraction but identical
(i.e., the same type) on the language level.

Is it?

Under what circumstances will I benefit from knowing that two types which
are logically distinct are actually physically the same? What will I do
with that information?
There are declarations that do create new types, and they do
something that typedef does not. Saying that typedef creates a
"new type" makes it difficult to discuss that important distinction.

True. I think that's why I like "define" -- definitions are not usually
expected to create new words.

-s
 
J

Joshua Maurice

"signed int", "int".

I think that and equivalent things are about it.  I might actually also
agree to things like, say, "uint32" and "u_int32_t" or whatever, where it's
clear that both are intending to denote the same thing.

Intention is irrelevant. You may intend for them to be two different
things, and they are two different things in your model, but they may
not be two different types in the C programming language. Types in the
C programming language are defined with regards to the type checker.

signed int * x;
int * y = x; /*success, different names for same type*/

"signed int" and "int" refer to the same type because the type system
of the standard, the compiler, and the compiler's type checker says
they do.

char * a;
signed char * b = a; /* compiler failure, incompatible types */
unsigned char * c = a; /* compiler failure, incompatible types */

Note that all 3 char types are distinct types, even though two of them
have the same bit representation, same manipulation rules, and are
otherwise identical /except/ that they are distinct types - the type
checker will not treat them as equivalent names. "signed char",
"char", and "unsigned char" are three distinct types because the type
system of the standard, the compiler, and the compiler's type checker
says that all three are distinct types.
 
J

Joshua Maurice

I'm not sure of this.  Here's my question, I guess:  Imagine that we
were to program in a hypothetical language to be called "C!".  And C!
is precisely identical to C, except that typedefs are always viewed
as incompatible with any other type.

What would we really have to change in our programs?  I wouldn't change
much of anything.  I don't think that language would be worse than C,
or even substantially different in terms of actual code I write or much
of the code I've read.  In fact, the only cases I can think of where code
would be invalid in "C!" would be cases where the code was wrong in C,
but the compiler couldn't tell.  (Counting only real code, not examples
intended to illustrate aspects of the type system.)

Admittingly, I can't think of a simple example in C, but in C++, I
have to know this to not write:
#include <stddef.h>
void foo(std::size_t ) {}
void foo(unsigned long ) {}
because that might compile on some implementations, and it might not
compile on others. Thus it is required to know that size_t is just an
alias for an already defined type to avoid writing bad code in C++.

For C, I can't think of an example offhand where you might write bad
code if you didn't know that size_t was merely an alias for an already
existing type because there's no function overloading. However, it is
still required to know that to explain to someone new why some "bogus"
code might compile when it should not, such as:
#include <stddef.h>
int main()
{
size_t * x;
unsigned int * y = x;
}
How else do you explain to someone why the above compiles on platform
X besides that typedef does not create new types and that size_t is
merely a different name for an already defined type?
 
J

Joshua Maurice

Joshua Maurice said:
The usage of the term "define a type" in the programming world at
large, and in the C community, means "to define a /new/ type" or
"introduce a /new/ type". Specifically, the just-introduced type must
be distinct from all other types (in that translation unit) -
[snip elaboration]

This statement may be true of some parts of the C community, but
certainly it is not true for all.  That also applies to the
programming world at large.

Now you have me curious. In what other programming contexts does
"define a type" carry a different meaning besides "introduce a new
type to the compiler which is distinct from all other types in the
current 'translation unit' (quote unquote) - distinct according to the
type system and the type checker"?

This is obviously specific to statically typed languages. The obvious
extension for dynamically typed languages is substitute "the runtime
type checker" in place of "the compiler type checker".
 

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,085
Messages
2,570,597
Members
47,220
Latest member
AugustinaJ

Latest Threads

Top