Am I being too C++ like?

J

Jorgen Grahn

.
In many cases a well_chosen name can actually _add_ some information. Consider
something like:

typedef unsigned int ipaddr_t;

and speculate what variables of this type are used for.

I strongly prefer the BSD sockets solution:

struct in_addr {
unsigned s_addr;
};

Your ipaddr_t can easily be confused with normal integers. The struct
cannot -- it's unique.

/Jorgen
 
K

Kleuske

I strongly prefer the BSD sockets solution:

struct in_addr {
unsigned s_addr;
};

Your ipaddr_t can easily be confused with normal integers. The struct
cannot -- it's unique.

/Jorgen

<sigh>

Again... The point was not to provide a way of dealing with IP-addresses
(v4 or v6), but to illustrate the point that a well chosen name for a
typedef can actually _add_ information.

I consider that point made.
 
N

Nick Keighley

     Not very effectively, since you need to rediscover at least
some of the "hidden" information before you can use `a'.

unless you are using it a completly opaque type

T t = create_T ();
operation1_t (t, 1, 2);
operation2_t (t, 1, 2);
print_t (t);
destroy_t (t);

The actual type of T could be completly hidden and yet be useful.
        a = 42;          // legal?
        *a |= 42;        // legal?
        a.fizz = 42;     // legal?
        a->buzz = 42;    // legal?
        puts(a);         // legal?
        longjmp(a, 42);  // legal?
        a(42);           // legal?

     As a matter of personal taste I rather like typedef aliases
for struct types

I happen not to like the "struct" keyword scattered all over the place
so I'm happy to hide it behind a typedf. This is something I think C++
gets right.
(and less often, union types),

I hardly ever use them. I do use typedefs with enums.
and I intensely
dislike them for data pointer types
ditto.

(but sometimes use them for
function pointers).

definitely, I think function pointer syntax is a bit nasty, and as
soon as you try and pass a function pointer as a parameter or return
it or make an array of them or have them as members of a struct the
readability plummets.
 For scalar types, I use typedef not so much
for opacity but for portability, using <limits.h> and #if to find
a type with suitable range and publishing the result as a typedef
name.

I quite like Byte or Octet because they state their intended use and
involve less typeing!
 
N

Nick Keighley

In C, it's normal to hardcode simple structures like stacks.

and I'm not convinced this is a good idea. I've seen code where
application and (much more) container management code were intimately
intertwined. You can no longer see the beef for the tree (to
intertwine metephors).

I think this "In C, it's normal to hardcode simple structures like
stacks" slides you towards this.
 
J

Jens Gustedt

Am 01/22/2012 03:22 AM, schrieb James Kuyper:
That's an example of why the macros
governed by 7.18.4p3 cannot contain casts.

They can contain casts, you just have to trick the preprocessor.

(0u+((uint128_t)+(X)))

works. For prepocessor evaluation this is (0u+((0)+(X)), so this will
evaluate to an unsigned quantity of value X. Since the preprocessor
calculates with uintmax_t, this is best what you can get.

For later translation phases this is a cast of +(X) followed by an
addition, which is fine, too.

Jens
 
B

Ben Bacarisse

Nick Keighley said:
unless you are using it a completly opaque type

T t = create_T ();
operation1_t (t, 1, 2);
operation2_t (t, 1, 2);
print_t (t);
destroy_t (t);

The actual type of T could be completly hidden and yet be useful.

I realise you are responding to the comment that you need to be able to
tell something about T to use it by giving an example where all the uses
are covered by function calls, but the last remark is still not true.

To declare an object of type T, it can't be "completely hidden" -- at
best it can be a pointer to an incomplete type. It's possible that you
intended to write

T *t;

in which case we know something about t (it's a pointer) and almost
nothing about T.

The trouble with making a type like T declarable, is that the users of
your interface will think that Ts are copyable without knowing what that
means. For example:

T save, t = create_T();
save = t;
operation1_T(t, 1, 2);
t = save

Does this restore the state or not? Of course this can be cleared up in
the documentation, but using a pointer to an incomplete type make things
clear. My own preference is to make "abstract" types declarable only
when they are copyable.

<snip>
 
J

Jorgen Grahn

and I'm not convinced this is a good idea. I've seen code where
application and (much more) container management code were intimately
intertwined. You can no longer see the beef for the tree (to
intertwine metephors).

I think this "In C, it's normal to hardcode simple structures like
stacks" slides you towards this.

+1.

I saw an example recently too. A queue of struct Foo, and batch
processing of these struct Foo off the queue. These two things
intertwined was /much/ harder to understand (and debug, and test, and
document, and ...) than the two parts.

/Jorgen
 
J

Jorgen Grahn

<sigh>

Again... The point was not to provide a way of dealing with IP-addresses
(v4 or v6), but to illustrate the point that a well chosen name for a
typedef can actually _add_ information.

I was /not/ talking about IP addresses -- I showed how the typedef
with the well-chosen name was still inferior to a new type. That this
happened to be a well-known example from the real world was a bonus.

/Jorgen
 
B

Bill Reid

Only total dorks feel the need to tell people who they've killfiled.
It's what I call the "talking kill-file"...it's the emotional
equivalent of a six-year-old putting their hands over their
ears and screaming when their parents try to discipline them...
Kiki fits the bill admirably.
Well, there's a couple of fun things about talking kill-files.
First, in my experience, most of them are imaginary, they never
kill-filed anybody in the first place, just like saying they
did because they think that somehow it "hurts" the victim's
feelings...

Which ties in with the second fun thing, you can say anything
you want to a person who claims they kill-filed you, and they
can't respond even if they lied and read it, because then everybody
would know they're a liar...but they usually crack and respond,
and that's just great fun (Mr. Thompson probably uses an imaginary
kill-file based on his response above, which makes him even
LESS mature than the screaming six-year-old).
 
K

Kleuske

I was /not/ talking about IP addresses -- I showed how the typedef with
the well-chosen name was still inferior to a new type. That this
happened to be a well-known example from the real world was a bonus.

<Whoosh...>

<sigh again>

Ok. You win. Happy?
 
S

Stefan Ram

My take is that this is neither C++ like nor OO like, but instead is
the older concept of an abstract data type.

1967 Alan Kay coins »object-oriented programming«,
Simula 67 [Dahl 66] has objects and classes

1974 Barbara Liskov publishes »Programming with Abstract Data Types«
 
T

Tim Rentsch

Jorgen Grahn said:
If you really care, you should really provide some arguments,
like us "naysayers" did ...

You mean arguments like "I don't like using typedefs"? I didn't
see any comments in this thread that amounted to anything more
than a statement of personal preference or opinion, from those
opposing the use of typedefs. OTOH, there were several comments
from people in favor of typedefs that gave reasons to prefer
typedefs (in some cases) that are at least somewhat objective,
rather than just stating a preference.
 
K

Keith Thompson

Tim Rentsch said:
You mean arguments like "I don't like using typedefs"? I didn't
see any comments in this thread that amounted to anything more
than a statement of personal preference or opinion, from those
opposing the use of typedefs. OTOH, there were several comments
from people in favor of typedefs that gave reasons to prefer
typedefs (in some cases) that are at least somewhat objective,
rather than just stating a preference.

A typedef for a struct type creates a new name (such as "foo") for a
type that already has a perfectly valid name (such as "struct foo").
The "struct foo" name still has to be used inside the struct definition
if the type declares a pointer to the same type (unless you use a
forward declaration). Using distinct identifiers for the tag and the
typedef name are different identifers, which is very common, can lead to
confusion.

Using a typedef for a struct type has few benefits. The drawbacks are
not terribly serious if you do it right, but in my opinion the benefits
are minor enough that it's not worth doing.

Of course if you think that having a one-word name for a type is a
significant benefit, then you're going to disagree with this argument.
 
K

Keith Thompson

Keith Thompson said:
A typedef for a struct type creates a new name (such as "foo") for a
type that already has a perfectly valid name (such as "struct foo").
The "struct foo" name still has to be used inside the struct definition
if the type declares a pointer to the same type (unless you use a
forward declaration). Using distinct identifiers for the tag and the
typedef name are different identifers, which is very common, can lead to
confusion.
[...]

Poor editing on that last sentence; I meant:

Using distinct identifiers for the tag and the typedef name, which is
very common, can lead to confusion.
 
S

Shao Miller

A typedef for a struct type creates a new name (such as "foo") for a
type that already has a perfectly valid name (such as "struct foo").
The "struct foo" name still has to be used inside the struct definition
if the type declares a pointer to the same type (unless you use a
forward declaration). Using distinct identifiers for the tag and the
typedef name are different identifers, which is very common, can lead to
confusion.

Using a typedef for a struct type has few benefits. The drawbacks are
not terribly serious if you do it right, but in my opinion the benefits
are minor enough that it's not worth doing.

Of course if you think that having a one-word name for a type is a
significant benefit, then you're going to disagree with this argument.

If I have 'struct cat' and want an instance, or even a pointer to such,
I might like to name the instance (or pointer) 'cat'.

struct cat * cat;

But that's no good, so maybe I'd do:

struct s_cat * cat;

That seems better, but if I have the 's_' there to indicate a 'struct'
type, I might as well 'typedef' it:

typedef struct s_cat s_cat; /* or maybe */
typedef struct s_cat S_CAT;
S_CAT * cat;

....Or such.
 
K

Keith Thompson

Shao Miller said:
A typedef for a struct type creates a new name (such as "foo") for a
type that already has a perfectly valid name (such as "struct foo").
The "struct foo" name still has to be used inside the struct
definition if the type declares a pointer to the same type (unless
you use a forward declaration). Using distinct identifiers for the
tag and the typedef name, which is very common, can lead to
confusion. [I've corrected the wording in the above paragraph]
Using a typedef for a struct type has few benefits. The drawbacks are
not terribly serious if you do it right, but in my opinion the benefits
are minor enough that it's not worth doing.

Of course if you think that having a one-word name for a type is a
significant benefit, then you're going to disagree with this argument.

If I have 'struct cat' and want an instance, or even a pointer to such,
I might like to name the instance (or pointer) 'cat'.

struct cat * cat;

That's perfectly legal, since the two "cat"s are in different
namespaces.

But it's a bad idea; surely if the type is "cat" or "struct cat", the
name of a single instance of the type should have a more specific name.
If nothing else, you could call it "the_cat".
But that's no good, so maybe I'd do:

struct s_cat * cat;

That seems better, but if I have the 's_' there to indicate a 'struct'
type, I might as well 'typedef' it:

typedef struct s_cat s_cat; /* or maybe */
typedef struct s_cat S_CAT;
S_CAT * cat;

That all seems unnecessary.
 
T

Tim Rentsch

Keith Thompson said:
A typedef for a struct type creates a new name (such as "foo") for a
type that already has a perfectly valid name (such as "struct foo").

Not necessarily; as long as struct type is not self-referential,
it can be typedef'ed without using a tag.
The "struct foo" name still has to be used inside the struct definition
if the type declares a pointer to the same type (unless you use a
forward declaration).

The cost of doing either of those is small. Besides, the most
important use case for typedef'ing a struct is to make a
(mostly) opaque type, in which case the header file will
forward-declare the struct type (without defining its contents)
along with the typedef, so the incremental cost of doing
a forward declaration is zero.
Using distinct identifiers for the tag and the typedef name are
different identifers, which is very common, can lead to confusion.

I can't really parse your sentence, but in any case it seems
mostly orthogonal to the question about whether it's a good
idea to use a typedef. Even though tags and typedef names
are in different name spaces, there can be confusion between
them, and they should be chosen with that possibility kept in
mind. It's easy to avoid confusion just by following some
sort of naming convention, such as (for example) appending
an '_s' to any struct tag that has an associated typedef.
(Or whatever other convention is suitable for the context,
that was meant just as an example.)

Using a typedef for a struct type has few benefits. The
drawbacks are not terribly serious if you do it right, but
in my opinion the benefits are minor enough that it's not
worth doing.

You haven't listed any of what you think are benefits.
I'm curious to know what those might be.

Of course if you think that having a one-word name for a type
is a significant benefit, then you're going to disagree with
this argument.

To my way of thinking the main reason to use typedef names
is to encourage use of information hiding and viewing of
various entities as abstract data types. In most cases, as
far as client code codes, the less one knows about a data
type the better; similarly, the more a type is treated as
an abstract data type, the better. The main cost of using
raw struct types is not in the typing but in the thinking:
for most code, not only do I not want to know what sort of
thing is being handled, I want NOT to know, because knowing
clutters ones thinking. Using a typedef name doesn't
prevent me from knowing (since after all I can go look at
the typedef in whatever header file defines it), but it
makes it easy not to know if one is so inclined. (And
those not so inclined can always just go look...)
 
R

Rui Maciel

Keith said:
Using a typedef for a struct type has few benefits. The drawbacks are
not terribly serious if you do it right, but in my opinion the benefits
are minor enough that it's not worth doing.

Do you see the ability to abstract types as being a benefit which is minor
enough that is not worth doing?


Rui Maciel
 
K

Keith Thompson

Tim Rentsch said:
Not necessarily; as long as struct type is not self-referential,
it can be typedef'ed without using a tag.

True. But that creates an artificial distinction between
self-referential and non-self-referential structs. My point is
that if you have a tag, you don't need a typedef.
The cost of doing either of those is small. Besides, the most
important use case for typedef'ing a struct is to make a
(mostly) opaque type, in which case the header file will
forward-declare the struct type (without defining its contents)
along with the typedef, so the incremental cost of doing
a forward declaration is zero.

Yes, if you want an opaque type, a typedef is perfectly appropriate; I
should have mentioned that. By "opaque" in this case, I mean that the
code that uses the type doesn't need to know or care that the type is a
struct.

I haven't seen a whole lot of code like that. It's more common, at
least in code I've seen, to declare a typedef for a struct type and then
write code that freely refers to its members.
I can't really parse your sentence,

Bad editing on my part; delete "are different identifiers".
but in any case it seems
mostly orthogonal to the question about whether it's a good
idea to use a typedef. Even though tags and typedef names
are in different name spaces, there can be confusion between
them, and they should be chosen with that possibility kept in
mind. It's easy to avoid confusion just by following some
sort of naming convention, such as (for example) appending
an '_s' to any struct tag that has an associated typedef.
(Or whatever other convention is suitable for the context,
that was meant just as an example.)

Too may programmers *don't* follow any particular convention.
I see plenty of code like:

typedef struct foo {
/* ... */
} bar;

where the names "foo" and "bar" don't have any particular relationship.

Strictly following some naming convention (like "typedef struct foo_s {
.... } foo") is better, but that's still two different identifiers to
keep track of. Using the same identifier for both is even better.
You haven't listed any of what you think are benefits.
I'm curious to know what those might be.

I mentioned it later: it gives the type a name that's a single
identifier, and saves a little typing.
To my way of thinking the main reason to use typedef names
is to encourage use of information hiding and viewing of
various entities as abstract data types.
[...]

I agree that that's the main *appropriate* reason to use typedefs for
structs. Unfortunately, it's not the main reason programmers actually
use them.
 

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,079
Messages
2,570,575
Members
47,207
Latest member
HelenaCani

Latest Threads

Top