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

J

Joshua Maurice

This is a pretty interesting claim. How does it mesh with your understanding
of the phrase "to define a word"? How about "to define an inline function"?

I cover that in that same post, further down. You also directly
replied to it. See there.
7.17 Common definitions <stddef.h>

The following types and macros are defined in the standard
header <stddef.h>.

The *types* are *defined*.

Please see: 6.2.1 Scope of Identifiers / 5. (I refers to section 6
instead of 5 in the previous post.) It specifically says when the
standard talks about an identifier X, they really mean to talk about
the thing to which the identifier refers, unless otherwise explicitly
stated. So, under that reading, types are defined.

However, I point you to "7.17 Common definitions <stddef.h> / 4",
which says that the recommended practice is to define size_t with a
typedef. So, when the standard says "The following types and macros
are defined in the standard header <stddef.h>", the standard writers
explicitly stated that the recommended way to "define" those types was
with typedef.

Next, "6.7.7 Type definitions / 3" says that "A typedef declaration
does not introduce a new type, only a synonym for the type so
specified". So, that means that the recommended practice is that
size_t is only a synonym for another "basic" type, and not a new
type.

Thus I posit that "The following types and macros are defined in the
standard header" is simply shorthand or an oversight for "the
following type /names/ and macros are defined in the standard
header".
If there were, there would be a crucial distinction to be drawn between
"defining a type" and "defining a type name". But there isn't. So there
isn't. What's left is to observe the consistent usage of phrases
such as "types ... are defined" to refer to the definition of type-names.

Did you read 6.2.1 Scope of Identifiers / 5. It very clearly calls out
that there is a difference between the nam and the thing to which the
name refers.
Given:
extern signed long sl;
extern signed short ss;
and assuming that both objects hold values which are not trap
representations, consider:
ss = sl; /* may be undefined behavior */
sl = ss; /* is not undefined behavior */

This has absolutely nothing to do with type safety. Do you even know
what a type system is?
No, it isn't.


I am not convinced that we can draw this conclusion. We certainly know
they're compatible. We know that types which are the same type are
compatible. However, this does not mean that there is no other way that
two types could be compatible.

True. See
6.2.7 Compatible type and composite type / 1
It has an attached note.
46) Two types need not be identical to be compatible.

However, it appears that only obscure scenarios allow for distinct
types to be compatible. See
6.2.7 Compatible type and composite type / 3
and
6.2.7 Compatible type and composite type / 5

Neither "struct foo" and "bar" are type "void", so they must be the
same type. There is no other explanation.

Wait a minute. Here's a fun one.
int main()
{
typedef void my_void;
my_void * x;
int * y = x;
}
This is well formed code. It compiles. There is a specific allowance
that says a type of "void pointer" can be assigned to any pointer
type. How the hell do you explain why this is well formed code without
acknowleding that "my_void" is the type "void", then applying the
"void pointer" allowance to convert it to "int pointer"?
I don't think so, simply because the common English meaning of the word
"define" is unambiguously "sane". To give a definition of; not to create.


It's not different from the sense in which I would usually talk about
defining a type.


Well, you will sometimes. Or perhaps it's two words which happen to be
written the same. :p


But something else could define a different word to be the same thing.

colour, n.: Alternative spelling of color.

Behold! It is a definition. It does not create a word. It does not
"redefine" another word. And yet, it defines one word to be the same
as another.

It depends on your particular definition of "create". Generally
programmers say that they "create" types when they write "struct foo
{ int x; };". I don't want to discuss Platonic ideals or anything
else. That's just the way it is.

You really are inventing definitions now. It doesn't "redefine"
another word. "To redefine" means to take something which already has
a definition, toss out that old definition, and give it a new one.
There is no ambiguity there.

Finally, this disputes nothing which I've said. I've said that when a
word is defined in a dictionary, it happens only once. You will only
ever find one entry for any particular word. This is no way rules out
homonyms.
To sum this all up, I have yet to see any contradictory usage of the
terms from reliable text, such as a programming language definition, a
paper written by a programming language expert, etc.

I suppose people who were involved with writing the standard are not
technically "experts", true.

But I've given many examples of contradictory usage in the standard itself.
In particular, the standard seems quite clear and consistent in treating
"typedef name" and "type" as essentially interchangeable while discussing
the behavior of the standard headers. Types and macros are defined
in <stddef.h>. We are told that <stdint.h> "declares sets of integer types",
and then we see "... <stdint.h> shall declare that typedef name and
define the associated macros." In 7.18.1.1, we see:
The typedef name intN_t ...
[...]
These types are optional.

In 7.18.1.2, after introducing "the typedef name int_leastN_t", the standard
goes on to say "The following types are required:", and lists typedef names.

In short, the standard is quite consistent about not being consistent in
this; the terms are repeatedly treated as functionally interchangeable.

It is a lack of consistency in word choice, but not an inconsistency
in the definitions and terms. Most of that isn't as bad as you make it
out to be. Remember that every definition is a declaration, so they
can say "declare" if it's a "definition". It's logically valid.

Also, due to the lack of perfection of the standard, this is why I
invoked other standards, other papers, and so on, besides just relying
on a single document made by man. Yet you immediately attack me about
talking about the C++ standard (just below). Thus you can have your
cake and eat it too, and apparently be the sole arbiter on the meaning
of words in programming.
This is completely irrelevant; the C++ standard and the C standard disagree
on a great deal of terminology.


Only you haven't. You've repeatedly asserted it, but you have yet to
demonstrate that the alternative model I use is incorrect or contradicts
the standard any worse than yours does. (Both contradict at least some
of the text, since the text itself is pretty much agnostic on the issue.)

If we start with the clear language in the standard governing "defining
typedef names" (which is clearly and unambiguously correct), and combine it
with the general disregard for any hypothesized distinction between typedef
names and types, we find that it is perfectly reasonable to refer
to typedef as "defining types", because the language spec does not
consistently distinguish between typedef names and types.

So far as I can tell, the standard has two modes of discussion of this. One
is the sense in which a distinction is being drawn between creating a new
type and merely creating a synonym for it, and in this context, we find
that typedef is merely defining "typedef names". The other is the sense
in which we are not talking about the underlying mechanics, but the effect
on a program, and the way a programmer interacts with type names; in this
sense, we find that "defines an identifier to be a typedef name" and "defines
a type" are functionally interchangeable.

In short, if you just want to write code, you can refer to typedef as
defining types, and nothing will go wrong. If you want to write a compiler,
there will be an afternoon or so during which you need to distinguish between
"new types" and "new typedef names", after which it stops mattering again.

Now, it's entirely possible that you know a great deal more about the standard
than the people who wrote it, and that we were all fools to refer to headers
as defining types, but it seems more reasonable to me to just assume that we
used that wording because it was clear, unambiguous, and communicated
correctly what it needed to communicate.

What is the meaning of define a type in your world? In my world, "to
define a type" means to create a new type which is distinct from all
other types according to the type system. Do you believe that "declare
a type name", "define a type name", "declare a type", "define a type",
and "define a new type" are all equivalent?
 
J

Joshua Maurice

This is a non-sequitur.

We are talking about the intention of a programmer as relevant to whether
we should view a typedef'd name as a new type even though it may be an
alias for some other type.

From the standpoint of someone hoping to write maintainable code, the
answer is "yes" -- you should treat each typedef as though it were an
incompatible type.

I don't think I've ever seen code which would be broken if the C
standard suddenly declared that typedefs were incompatible with the types
with which they wer synonymous, unless it was already conceptually
broken.

You fail. It is quite common to use typedefs to work around the
atrocious type declaration syntax of C. Ex:
typedef int (*foo_t) (short*, long*);
typedef foo_t* (*bar_t)(int );
bar_t* baz();
I could attempt to write that out in a single declaration of function
baz, but it would be insane to do so. It would also be rude to users
to force them to write their own typedefs, as it would also be insane
for them to try and write out the "full form" of the types.
 
J

Jon

Rui said:
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.



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.

You kids are annoying.
 
S

Seebs

Please see: 6.2.1 Scope of Identifiers / 5. (I refers to section 6
instead of 5 in the previous post.) It specifically says when the
standard talks about an identifier X, they really mean to talk about
the thing to which the identifier refers, unless otherwise explicitly
stated. So, under that reading, types are defined.
Yes.

However, I point you to "7.17 Common definitions <stddef.h> / 4",
which says that the recommended practice is to define size_t with a
typedef. So, when the standard says "The following types and macros
are defined in the standard header <stddef.h>", the standard writers
explicitly stated that the recommended way to "define" those types was
with typedef.

Yes.

And that tells us that typedef defines types.

Because you use a typedef to do it, but what you do is define types.

Conclusion: Typedef defines types. Period.
Next, "6.7.7 Type definitions / 3" says that "A typedef declaration
does not introduce a new type, only a synonym for the type so
specified". So, that means that the recommended practice is that
size_t is only a synonym for another "basic" type, and not a new
type.
Yup.

Thus I posit that "The following types and macros are defined in the
standard header" is simply shorthand or an oversight for "the
following type /names/ and macros are defined in the standard
header".

In other words:

"types are defined" is perfectly valid, clear, coherent, and reasonable.
And refers to what "typedef" does. But, for the one afternoon out of
the entire development of a compiler that you're working with typedef, you
have to remember that actually it's shorthand for "defines type names".
Did you read 6.2.1 Scope of Identifiers / 5. It very clearly calls out
that there is a difference between the nam and the thing to which the
name refers.

Yes. However, in the case of a type, where there's no object or object
code, it's a largely irrelevant distinction.
This has absolutely nothing to do with type safety. Do you even know
what a type system is?

Yes. However, it is a clearcut case where you can substitute types in
one way but not another. The relations between types are not always
commutative.
However, it appears that only obscure scenarios allow for distinct
types to be compatible.

The use of multiple translation units is hardly an "obscure" scenario!
Wait a minute. Here's a fun one.
int main()
{
typedef void my_void;
my_void * x;
int * y = x;
}
This is well formed code. It compiles. There is a specific allowance
that says a type of "void pointer" can be assigned to any pointer
type. How the hell do you explain why this is well formed code without
acknowleding that "my_void" is the type "void", then applying the
"void pointer" allowance to convert it to "int pointer"?

I am having a hard time seeing why this should be surprising.

Obviously, if we make a new "type" (in the sense of a type-name), it will
have the exact same characteristics as the type it's the same as.
It depends on your particular definition of "create". Generally
programmers say that they "create" types when they write "struct foo
{ int x; };". I don't want to discuss Platonic ideals or anything
else. That's just the way it is.

I don't say that I "create" types. I say that I *define* types. The
standard's language is pretty consistent on this; objects are created,
types are defined.
You really are inventing definitions now. It doesn't "redefine"
another word. "To redefine" means to take something which already has
a definition, toss out that old definition, and give it a new one.
There is no ambiguity there.

Indeed, there isn't. That was my point. I'm not redefining a word; I'm
defining it, and it's now the same as another word.
Finally, this disputes nothing which I've said. I've said that when a
word is defined in a dictionary, it happens only once. You will only
ever find one entry for any particular word. This is no way rules out
homonyms.

I would tend to agree. However, dictionaries are not quite the same thing
as programs.
It is a lack of consistency in word choice, but not an inconsistency
in the definitions and terms.

It's not an inconsistency in terms as long as you recognize that the standard
writers quite clearly considered typedef to define types. Once you
have that, everything works beautifully.
Also, due to the lack of perfection of the standard, this is why I
invoked other standards, other papers, and so on, besides just relying
on a single document made by man.

Ahh, but see.

The question is not what the C standard *should* have said about definitions.

The question is whether a C programmer, familiar with the standard, could
reasonably claim that typedef defines types.

I would say that, given that the people who wrote the standard referred to
typedefs as type definitions, and said that types introduced via typedef
were "defined" in the headers doing so, that it would be a pretty reasonable
way to describe what happens.
Yet you immediately attack me about
talking about the C++ standard (just below).

I don't attack you, I just regard it as completely irrelevant.
What is the meaning of define a type in your world?

At least when talking about C, precisely the meaning the standard uses.
In my world, "to
define a type" means to create a new type which is distinct from all
other types according to the type system.

So you've said. You have not offered anything to suggest to me that this
usage is consistent with the C language system, or that it's a particularly
useful usage.

The language spec never says that to "define a type" is "to create a new
type which is distinct from all other types". Instead, we *repeatedly*
see "type definitions", "types are defined", and similar words used to
refer to "creating a new type name which is quite possibly an alias of
sorts for some other type".

I do not expect "defining" a word to require that I am "creating" a new
word which is distinct from all other words. In fact, I seem to recall that
some dictionaries do, in fact, offer multiple definitions for some words;
you may find that alternative spellings of a word are listed both as separate
entries and as part of the main entry, each occurrence being a definition
of that word.

I do not expect "defining" a type to have anything to do with whether it is
being "created" or not created, or whether it is "new", or whether it is
"distinct from all other types". All I expect it to do is be something
before which the type was not known, and after which the type is known and
defined. That's it.
Do you believe that "declare
a type name", "define a type name", "declare a type", "define a type",
and "define a new type" are all equivalent?

No, although they are very often used to refer to the same things.

-s
 
S

Seebs

You fail.

My, you're a friendly sort.
It is quite common to use typedefs to work around the
atrocious type declaration syntax of C. Ex:
typedef int (*foo_t) (short*, long*);
typedef foo_t* (*bar_t)(int );
bar_t* baz();
I could attempt to write that out in a single declaration of function
baz, but it would be insane to do so. It would also be rude to users
to force them to write their own typedefs, as it would also be insane
for them to try and write out the "full form" of the types.

You raise an interesting point here. I think there may well be cases like
this in which typedef is used to simplify spelling something out, rather
than to create a logically distinct type. That said, I'm not sure I've
seen any code which uses such typedefs but only uses them sometimes, such
that it would be broken if a fully-spelled-out declaration of baz() were
incompatible with the bar_t * form.

But this does suggest a category of usage where it might be an issue;
conceivably, there could be code inside a library which uses the raw
declaration for which FILE is an alias, for instance.

-s
 
J

Joshua Maurice

My, you're a friendly sort.

Indeed. You talk as though you know something, but your lack of
knowledge of C, type theory, and general programming nomenclature is
getting to me. I'm getting close to the point of concluding that
you're trolling.
You raise an interesting point here.  I think there may well be cases like
this in which typedef is used to simplify spelling something out, rather
than to create a logically distinct type.  That said, I'm not sure I've
seen any code which uses such typedefs but only uses them sometimes, such
that it would be broken if a fully-spelled-out declaration of baz() were
incompatible with the bar_t * form.

But this does suggest a category of usage where it might be an issue;
conceivably, there could be code inside a library which uses the raw
declaration for which FILE is an alias, for instance.

More specifically, example:
typedef int (*foo_t) (short*, long*);
typedef foo_t (*bar_t)(int );
bar_t baz();

foo_t x(int x) { return 0; }

bar_t baz() { return &x; }

In the function body of baz, the compiler type checker checks to
ensure that the type of "&x" is compatible with "bar_t".

If you use typedefs in the function declaration of baz, and you want
to return an actual function pointer to a function of "that type",
then the typedef must be the same type as the "referred to" type. In
other words, the (static) type of "x" must be equivalent to "bar_t".
In fact, because they're "equivalent", we can conclude that they are
the same type via "6.2.7 Compatible type and composite type". Thus
typedef types are the same type as the "original" type. It must be
this way. It is quite visible to the programmer, and it is quite
important.

So, we're left with
1- typedef does not define types
2- typedef defines a type which already exists, aka it redefines the
type (silly)
3- "define a type" is hopelessly vague (also silly)
 
S

Seebs

Indeed. You talk as though you know something, but your lack of
knowledge of C, type theory, and general programming nomenclature is
getting to me. I'm getting close to the point of concluding that
you're trolling.

Uh...

Again, I'm one of the people who wrote the spec you're quoting. If
you can't distinguish between "disagreement" and "lack of knowledge",
that's your problem.
If you use typedefs in the function declaration of baz, and you want
to return an actual function pointer to a function of "that type",
then the typedef must be the same type as the "referred to" type. In
other words, the (static) type of "x" must be equivalent to "bar_t".
In fact, because they're "equivalent", we can conclude that they are
the same type via "6.2.7 Compatible type and composite type".

I already pointed out the problem with this.

Equivalent types are not the same thing as "the same type". They do
have to be *identical*, but there is a distinction between that and
being the same thing. There can be two things which are identical.
Thus
typedef types are the same type as the "original" type. It must be
this way. It is quite visible to the programmer, and it is quite
important.

Only, in the vast, vast, majority of cases, it is something that's only
visible if you write code which is logically incorrect.

You've got a single contrived example. I've got every line of code
ever written that referred to or used a size_t.
1- typedef does not define types

Obviously wrong, since the standard clearly and repeatedly says it does.
2- typedef defines a type which already exists, aka it redefines the
type (silly)

This is a confusion on your part.

Again, I point you to the example of "colour".
colour, n.: Alternative spelling of color.

This clearly does not define "a new word". Rather, it informs you that
"colour" is actually just a different spelling of "color". They are the
same word. However, that's not "redefining" the type.

Redefining is when you present a different definition for the same name.
When you provide a different name for the same definition, that's *not*
redefining. But that's exactly what typedef does.
3- "define a type" is hopelessly vague (also silly)

This one's actually pretty viable. Quite simply, it never turns out to
matter. If you describe it as "typedef defines types, but some types are
interchangeable", everything works, you can write correct code, all the
wording in the standard works out fine. If you describe it as "typedef
defines names for types", everything works, you can write correct code,
all the wording in the standard works out fine.

The problem comes when you take your notion that defining a type *must*
mean "creating a new type which is distinct from all existing types", and
bolt it onto the language used in the standard. That notion was not part
of what we had in mind, and if you insist on shoving additional,
contradictory, premises into a text, you'll get nonsense -- but that's your
problem. Don't do that then.

The C standard's language about types and definitions simply does not
contain, or particularly work with, the premise that defining a type
must be creating a new type which is distinct from all existing types.

Instead, the standard handles the distinction by introducing the notion
of "compatible" types. With objects, you really do need to know whether
you have found the single "definition" the object can have. With functions
(other than inline functions), the same issue applies. However, when it
comes to types, there's no corresponding issue. Most compilers don't even
embed any knowledge of types in the code they generate except as part of
debugging symbols. There is no thing which is created when you "define"
a type. As such, it *does not matter*. You don't have to know whether a
given thing is "the" definition -- you can define the same type in each
of twenty translation units, and you've got twenty definitions, and SO WHAT?
No one cares. Heck, unless you're passing objects of that type around
between the units, they can be twenty DIFFERENT definitions, and still,
no one cares.

Given that, the importance of the distinction is largely gone. Add to this
the fact that typedefs are sometimes used to provide types which cannot
be referred to by any means other than the typedef, or at the very least,
which cannot be interchanged with anything else in portable code, and it
becomes entirely reasonable to simply refer to them as "defining types".

Yes, in theory, they are defining a name which then refers to a type. But
in practice, that's a distinction that never affects any actual code that
you need to write. It doesn't matter whether intmax_t is an alias for "long
long" or an alias for "__INTERNAL_USE_ONLY_INT_128_T". No one cares. All
that matters is that intmax_t is a thing you can use to declare objects
of the type intmax_t, and that such objects are large enough to hold any
integer that you can declare by any other means.

-s
 
J

Joshua Maurice

Yes.  However, it is a clearcut case where you can substitute types in
one way but not another.  The relations between types are not always
commutative.

You sir are an idiot. You do not know nothing about type safety, type
theory, type systems, and so on. This is not an example of a type
system. This is not an example of a "type error" according to the wiki
definition.

Type systems are inherently a trade-off between allowing potentially
"nonsensical" operations and providing a useful programming language.
In the above example, there are implicit conversions, though we could
write out explicit pseudo-code as follows:

extern signed long sl;
extern signed short ss;
int main()
{
ss = signed_long_to_signed_short(ss);
sl = signed_short_to_signed_long(ss);
}
The function signed_long_to_signed_short has domain (set of signed
longs), codomain (set of singed shorts). The domain has larger size
than the codomain. If this was a formal math function, then the
function would have to be not injective according to the pigeonhole
principle (my favorite principle name). However, programming functions
are defined slightly differently. Instead, one can say that the
function has "undefined behavior" over certain subsets of its domain.
In fact, the function signed_long_to_signed_short has formally
undefined behavior according to the C standard.

This is not a matter of type safety in any way. It's just that a
function from type A to type B has undefined behavior over part of its
domain.

Let's take an even simpler example. This is the stereotypical example
to introduce someone to type theory. In C, one might write a stack
abstraction as:
struct stack_t;
void stack_push(struct stack_t* , void* );
void* stack_pop(struct stack_t* );
The function stack_push is defined over all possible inputs (ignoring
finite memory and finite precision integer types for the moment).
However, the function stack_pop is not defined over all of its input.
Attempting to call stack_pop on an empty stack "does not make sense".
In the real world, what happens depends on its contract. It could say
"abort()", "undefined behavior", "return null", and so on. Whatever
you say though, it's not a type error to call stack_pop on an empty
stack given those declarations of stack_t and stack_pop.

However, one can make it into a type problem. C lacks the facilities,
but other languages can give it to you. Forgive my very pseudo-code
here. This is not my area of expertise. From my very limited
understanding, Haskell is like this to some degree.

Let's define the stack variable and the stack_pop function.

A stack is either an empty stack, or a non-empty stack.
stack = empty_stack | non_empty_stack

An empty stack is nothing.
empty_stack = ()

A non-empty stack is a pair of an int and a stack.
non_empty_stack = (int, stack)

The function stack_pop only makes sense on a non-empty stack, so let's
define it that way. It converts a non-empty stack into a stack without
its top element, and popped int.
function stack_pop : non_empty_stack -> (stack s, int i)

One could then use these definitions to declare a stack variable.
stack x

Then assign it to be a non-empty stack.
x = (1, empty_stack)

The following code would be illegal. stack_pop is not defined on the
type stack. stack_pop is defined only on non_empty_stacks.
(stack, int) z = stack_pop(x)

In this pseudo-code language, the compiler would fail the compilation
for the above line, saying something like
Line <X>: stack_pop called with arguments (stack)
no matching function found, name look
name lookup found:
stack_pop : non_empty_stack -> (stack , int )

Instead, you would have to do a cast of sorts to cast it to the
appropriate type.

IIRC, for some real programming language, the construct looks /very
vaguely/ like:
switch_on_type(x)
{
case empty_stack:
print("stack is empty");
case non_empty_stack:
(stack, int) z = stack_pop(x)
print(z.i)
}

In order to do a pop, I first have to do a cast to non_empty_stack.
Moreover, the construct requires that I supply code which handles all
possible types of the object. In the case where the x is indeed a
non_empty_stack, x's type is now treated as non_empty_stack, so I am
now allowed to call stack_pop on it.

However, I also have to handle the case where it is an empty stack.
Before where we might say "undefined behavior" in C, this hypothetical
programming language requires me to give it defined behavior. (Note
that this isn't required to make the error into a "type error". I
suppose one could define the language so that if there is no case for
the runtime type, it causes a crash.)

Notice that in the C example, you can call the function stack_pop with
any stack argument. The C type system lets you. The C type system does
not distinguish between an empty stack and a non-empty stack. However,
in my strongly pseudo code example reminiscent of Haskell, the type
system can and does distinguish between empty stacks and non-empty
stacks (and plain stacks). The example of undefined behavior on signed
overflow in C is /not/ an example of a type error, incompatible types,
or anything else related to type safety and a type system.

So, why don't we program in a language with such a "strong" type
system? As the wiki page on type systems explains, type systems are a
trade-off. It does a better job at explaining it than I could offhand.
It's been a while since I've had to explain type theory to anyone.
http://en.wikipedia.org/wiki/Type_system

This is only a beginning of type theory. I strongly suggest that you
read a book and fix your ignorance. Good day sir.
 
J

Joshua Maurice

Uh...

Again, I'm one of the people who wrote the spec you're quoting.  If
you can't distinguish between "disagreement" and "lack of knowledge",
that's your problem.

You were on the ISO team that drafted the ISO/ANSI C standard? For
shame then. What country do you represent on the ISO team? You really
ought to educate yourself and recuse yourself in the meantime before
you do any (more) damage to a wonderful programming language.
 
S

Seebs

You sir are an idiot.

So some people tell me.
You do not know nothing about type safety, type
theory, type systems, and so on.

I am not talking about the abstract theory of what types might look like
in some language other than C. I'm talking about how C works.

I am well aware that, in many languages, "types" work very differently
than they do in C. That's nice for them. On paper, it even looks as
though they may have better designs.

But in C, types are a lot quirkier than that.

All your expostulations here have nothing to do with the subject at hand,
which is not whether typedef defines "the things that we would call types
if we were writing in some totally different language".

-s
 
S

Seebs

You were on the ISO team that drafted the ISO/ANSI C standard?

Yeah, for about a decade.
What country do you represent on the ISO team?

None, at the moment.
You really
ought to educate yourself and recuse yourself in the meantime before
you do any (more) damage to a wonderful programming language.

Certainly, this is possible. However, I'm forced to choose between two
alternative hypotheses.

One is that some random guy on the internet I've never heard of who
had never read the standard until the last week or so was confused about
C, talked a big game, and got himself emotionally committed to winning a
point even though he'd misunderstood some of the details of C.

The other is that every C programmer I've ever known, or talked to, was
completely incompetent, including the other people I met while I was on
the C committee, compiler writers, library maintainers, and so on.

I'll have to think about this one for a while.

-s
p.s.: http://en.wikipedia.org/wiki/Dunning–Kruger_effect
 
J

Joshua Maurice

So some people tell me.


I am not talking about the abstract theory of what types might look like
in some language other than C.  I'm talking about how C works.

I am talking about how C works. You took off part of the quote in
which you said that this is an example of types which are incompatible
one way, but not the other. No. That is not the definition of
incompatible types even according to the C standard. Incompatible
types according to the C standard clearly deals with type system
constraint violations. C's type system is strictly static. Type errors
happen at compile time. No type information survives to runtime.
Signed integer overflow is not a type system constraint violation.
Signed integer overflow occurs at /runtime/. Thus the overflow /
cannot/ be a type error.
 
S

Seebs

I am talking about how C works. You took off part of the quote in
which you said that this is an example of types which are incompatible
one way, but not the other. No. That is not the definition of
incompatible types even according to the C standard.

Fair enough. I was off talking about which types you can assign
directly to each other, not which types are "compatible" in that sense.
I'm not sure that getting off onto a tangent in the middle of multiple
hundred-line posts quite rises to the level of idiocy, but it's important
to set your sights high, I always say.

What someone who was a little more interested in finding out what other
people are saying, rather than in declaring them wrong, might have wondered
about is why I brought it up. Sometimes, people go on tangents because they
think a point is potentially relevant.
No type information survives to runtime.

Indeed, in general, it doesn't even survive to link time.

Which is why the "definition" concept is different for types than it is
for objects and functions -- because you don't have linker problems if
you link two types that had the same name.

Every translation unit that has the definition of struct foo has its own
definition of a type "struct foo", and those types are compatible, but they're
actually different types -- they're just types which happen to be identical.

I've found that, for the most part, it's much more useful to treat
the majority of typedef'd types *as if* they were unrelated to the types
they're aliases for -- thus, no treating uid_t as if it were just int,
even though it may be.

Ultimately, there are several perfectly good ways to talk about what C's
type system does when it encounters a typedef, and the one I use is mostly
based on the way the standard talks about what headers do to provide you
with "types". I find it more useful to view size_t as a distinct type which
may by coincidence be indistinguishable from one of the other unsigned
integer types. Keith finds it more useful, apparently, to view it as being
one of those types, but you don't know which one. Either way works; both
of us write code which compiles predictably and portably and does what we
expect it to do.

-s
 
J

Joshua Maurice

Fair enough.  I was off talking about which types you can assign
directly to each other, not which types are "compatible" in that sense.
I'm not sure that getting off onto a tangent in the middle of multiple
hundred-line posts quite rises to the level of idiocy, but it's important
to set your sights high, I always say.

What someone who was a little more interested in finding out what other
people are saying, rather than in declaring them wrong, might have wondered
about is why I brought it up.  Sometimes, people go on tangents because they
think a point is potentially relevant.


Indeed, in general, it doesn't even survive to link time.

Which is why the "definition" concept is different for types than it is
for objects and functions -- because you don't have linker problems if
you link two types that had the same name.

Every translation unit that has the definition of struct foo has its own
definition of a type "struct foo", and those types are compatible, but they're
actually different types -- they're just types which happen to be identical.

I've found that, for the most part, it's much more useful to treat
the majority of typedef'd types *as if* they were unrelated to the types
they're aliases for -- thus, no treating uid_t as if it were just int,
even though it may be.

Ultimately, there are several perfectly good ways to talk about what C's
type system does when it encounters a typedef, and the one I use is mostly
based on the way the standard talks about what headers do to provide you
with "types".  I find it more useful to view size_t as a distinct type which
may by coincidence be indistinguishable from one of the other unsigned
integer types.  Keith finds it more useful, apparently, to view it as being
one of those types, but you don't know which one.  Either way works; both
of us write code which compiles predictably and portably and does what we
expect it to do.

Fine. I can't call that position idiotic. However, I can and will call
your supposition that "signed integer overflow is a type error"
retarded. You either have a very serious English problem, you have no
clue what you're talking about, or your brain left you for a short
period of time.
 
F

Felix Palmen

* Seebs said:
Yeah. This is why I avoid trying to find out whether, say, uid_t and
int are the same type -- there's no way I could use that information
to improve a program.

That really sums it up on the technical side. And I'd widen the scope a
little like this:

It's useful to know that typedef just creates a new name "internally" in
order to understand the lack of some error messages you may expect. But
this is pretty much¹ the only thing you could use this information for as
a programmer, at least as long as you want to write clean,
understandable and portable code.

Regards,
Felix

¹ There are corner cases like the 'reference types' I already mentioned
(that would be in C a pointer to a struct unknown to the caller, in
order to use an OO paradigm). If you want to forward declare them in the
headers for reducing the size of a compilation unit, you'll end up using
"struct foo *" for members of an object and just "Foo" in the calling
code, exploiting the fact that they really are aliases. But as long as
you don't have any circular dependencies, you can cope quite well
without such "tricks".
 
J

Joshua Maurice

Fine. I can't call that position idiotic. However, I can and will call
your supposition that "signed integer overflow is a type error"
retarded. You either have a very serious English problem, you have no
clue what you're talking about, or your brain left you for a short
period of time.

Sorry, but let me continue. I can accept that there is some basis to
say that typedef defines types. It would be wholy inconsistent with
everything in the programming world besides C, but hey, maybe that's a
reasonable interpretation.

Orly? I was reviewing the standard again, taking catalog of all uses
of the word "compatible", and I was going to form an argument based on
that. However, I stumbled across a great gem.

6.7.7 Type definitions / 4
EXAMPLE 1 After
typedef int MILES, KLICKSP();
typedef struct { double hi, lo; } range;
the constructions
MILES distance;
extern KLICKSP *metricp;
range x;
range z, *zp;
are all valid declarations. The type of distance is int, that of metricp is ‘‘pointer to function with no parameter specification returning int’’, and that of x and z is the specified structure; zp is a pointer to such a structure. The object distance has a type compatible with any other int object.

So, it clearly states that "the type of distance is int". There.
typedef does not define types. It defines type names which are aliases
for already-defined types. In this case, "MILES" is a type name which
is a synonym for "int". The declaration "MILES distance;" declares an
object of type "int". Thus "MILES" and "int" are both simply type
names for the same type, which we commonly call "int".

Need any more evidence? Going to say that this is a one off fluke, a
mistake in the standard? I'll keep going if need be.

I had a really great argument in the works, using the C definition of
"compatible", and how there is nothing which I've found thus far which
says that a typedef type is compatible with its original type, nor
that integer promotions apply to typedef types, nor "void pointer"
implicit rule applies to types typedef-ed on "void", etc. You need to
really read into the standard to get your position out of it.
 
J

Jon

Tim said:
Jon said:
Tim 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.

Yeah well why don't you take your fucking C and shove it up your ass.
 
B

Ben Bacarisse

Seebs said:
On 2010-10-23, Joshua Maurice <[email protected]> wrote:

Obviously wrong, since the standard clearly and repeatedly says it
does.

I think that is, at best, vastly overstating the case. If the standard
wanted to make this clear, why is this simple supposed fact about
typedefs not present in the section that defines and discusses typedefs?

More often than not (it is hard to count exactly) the standard is
careful to talk about typedef *names* being defined (and, unfortunately,
sometimes "declared"). If the intent was to be clear that typedefs
define types, why are there so many uses of the alternate wording?

7.18 seems to be an exception with what I consider to be some rather
confusing usage. The introduction talks about defining types but then
the subsections revert to what seem to me to be the more careful use of
language by talking about what typedef names must be defined and about
what types these names denote.

Sadly, 7.18.1.2 p3 then says "The following types are required" and goes
on to list some things that have been carefully described previously as
typedef names. I take that to be, at best, a shorthand. I don't think
it can be seen as a clear statement that typedefs define types.

Several other standard headers are described as defining types but I
take that as permission to do so by unspecified means. Of course, it
does imply that an implementation that uses typedef for this purpose is
using it to "define a type", but I would not go so far as to say this is
a clear usage of that phrase (mainly because it is simply implied).

Given how much you know about the standard, I can't help thinking that I
must have missed the repeated instances where it clearly says that
typedefs define types. But since the best place to state this clearly
would have been 6.7.7, I think I am permitted some scepticism on this
point. Like all good sceptics I am open to evidence and, if your
evidence is exactly those things which I find confusing, I am happy to
accept that we simply disagree about what constitutes a clear statement.
 
N

Nick Keighley

NickKeighleywrote:



Which is a hundred times better than "typedef", but does seem to
introduce compound words as keywords which is probably not necessary and
probably not desireable.

typedef, sizeof and offsetof all look pretty compound to me
 

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

Latest Threads

Top