Hello, I would like to typedef and replace the struct usage in UVM, so that struct vm_map would become vm_map_t, struct vm_anon - vm_anon_t, and so on. It increases readability and makes UVM consistent in this respect with other subsystems (cf. sys/kern). Any concerns? I would like to do this in one go, since <chs> has mentioned that "slow" diverge would prolong his pain. :) -- Best regards, Mindaugas
This sounds good. But I would utter a plea to please _not_ start creating similar typedefs for pointers to those structures. I, for one, find it borders on crippling for readability to see something like "foobar_t something;" and not realize until much later that it's actually a pointer. /~\ The ASCII Mouse \ / Ribbon Campaign X Against HTML mouse@rodents-montreal.org / \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
Hi! Sort answer: I strongly support "typedef struct vm_page *vm_page_t". Long answer: I've been looking deeply into UVM pager and the fault routine. I plan to extend pagers to handle not only page cache but also non-cache page, that is memory-mappable, directly-accessible page, like character devices or NAND FlashROM. To achieve this, I want pagers to return a magic (struct vm_page *) to tell callers that "there is no (struct vm_page *) object; we tell you my physical address other way!". Here (struct vm_page *) is actually a magic uintptr_t. I think that there're many benefits by making struct vm_page opaque. Its content is touched from ~everywhere including filesystem layers, which violates abstraction. I'd propose to make vm_page_t opaque and make users to always use accessor routines. If once vm_page_t internal is hidden, page handling would be much extensible - locking improvements, accounting, or variable sized pages, etc. Masao
Making data structures opaque is a completely different issue from creating an unnecessary and misleading layer of magic aliased names for them. -- David A. Holland dholland@netbsd.org
Strongly opposed to the _t mania. I actually had a longer mail written about the subject a few days ago, but I managed to lose it. My two main reasons for opposition were: 1) obfuscates code. there is no reason to tell if silly_t is an int, struct or pointer to something just by looking at the type 2) impossible to provide forward declarations for interfaces using silly_t
Or maybe Antti means: struct mystruct; int foo(struct mystruct *); That works with typedefs too, but you need to duplicate the typedef line: struct mystruct; typedef struct mystruct mystruct_t; int foo(mystruct_t *); eric
On Tue, Jun 16, 2009 at 12:45:22AM -0500, Peter Seebach wrote: > In message <20090616053752.GA8944@cs.hut.fi>, Antti Kantee writes: > >2) impossible to provide forward declarations for interfaces using > > silly_t > > int foo(silly_t); Or maybe Antti means: struct mystruct; int foo(struct mystruct *); That works with typedefs too, but you need to duplicate the typedef line: struct mystruct; typedef struct mystruct mystruct_t; int foo(mystruct_t *); duplicate typedefs generate an error. .mrg.
hmm.. you're right. It worked fine on the machines at work, but those are linux, not NetBSD. Still, I kind of figured gcc would behave the same. Oh well, I stand corrected. eric
On Wed, Jun 17, 2009 at 01:16:20AM +1000, matthew green wrote: > Or maybe Antti means: > > struct mystruct; > int foo(struct mystruct *); > > That works with typedefs too, but you need to duplicate the typedef line: > > struct mystruct; > typedef struct mystruct mystruct_t; > int foo(mystruct_t *); > > duplicate typedefs generate an error. hmm.. you're right. It worked fine on the machines at work, but those are linux, not NetBSD. Still, I kind of figured gcc would behave the same. Oh well, I stand corrected. i've never seen this work on any C platform. .mrg.
The fact that the latter is a bug, means that you can only define a typedef in one place This is a problem if the functions that use the type need to be in several header files - since you end up either putting the typedef in a global file, of a file of its own. In some places you'll see a 'struct foo' definition before a function prototype where everywhere else the typedef is used! From a language point of view there is little difference (other than the number of characters needed) between using 'struct foo' and 'foo_t' once 'typedef struct foo foo_t' is in scope. (Except that, in C (but not C++), the struct namespace is separate from all others.) David -- David Laight: david@l8s.co.uk
what about :
typedef struct {
....
} mystruct_t;
Though i dont know how to cleanly pre-define them other than
typedef struct mystruct_t;
Reinoud
Just to make this clear, I do not want to typedef structs as pointers. I agree that it is confusing (although it has a good rationale for some I am not sure what do you mean. Each typedef, eg. vm_page_t would be a structure, where vm_page_t * a pointer to it. No intention to typedef Why not? Note that struct declarations wont be removed (cf. struct lwp and lwp_t). -- Best regards, Mindaugas
The underlying problem is that I do not see any benefit from arbitrary There are plenty of places in the kernel where _t is a pointer. How are you supposed to distinguish between them? More specifically to this case, when vm_page_t existed in NetBSD with the Mach vm, it was a pointer. And, actually, opaque foo_t struct pointer is the only place where I ... see mrg's mail in this thread.
I understand that it is a personal preference, but at least to me, it would increase readability. It would be good to hear opinions of more people who are working in sys/uvm. Also, as already mentioned, this would be consistent with other core parts, I do not see a necessity to have any _t which would be a pointer in sys/uvm. Keep things simple. Historical point should not disturb, we have UVM now, Why do you need typedefs there? What's wrong with struct vm_page; ? As said, struct definitions stay, eg. your rump would not require any changes. -- Best regards, Mindaugas
Antti Kantee <pooka@cs.hut.fi> wrote: > > Just to make this clear, I do not want to typedef structs as pointers. > > I agree that it is confusing (although it has a good rationale for some > > cases, eg. when structure size is dynamic). > > The underlying problem is that I do not see any benefit from arbitrary > typedefs such as struct x -> x_t. Will we get u32_t next? I understand that it is a personal preference, but at least to me, it would increase readability. It would be good to hear opinions of more people who i generally prefer "struct foo". "foo_t" almost always send me off looking into some header file to see what it really means. > There are plenty of places in the kernel where _t is a pointer. How are > you supposed to distinguish between them? More specifically to this case, > when vm_page_t existed in NetBSD with the Mach vm, it was a pointer. I do not see a necessity to have any _t which would be a pointer in sys/uvm. Keep things simple. Historical point should not disturb, we have UVM now, not Mach VM. Solaris VM, for example, has structures typedef'ed. honestly, if you going to do this, please rename all the "struct vm_foo"'s to "struct uvm_foo". the current method with some of each is historical baggage to the integration of UVM and it has always bothered me. that would also avoid any confusion for folks with mach vm knowledge. .mrg.
If we rename struct vm_map to uvm_map, it conflicts with uvm_map(). Semantically fine, but lose readability, greppability, and ctags-ability. Masao
No, your argument is personal preference, mine is technical. This was already hinted a few times, but here we go again: If you have typedef struct foo foo_t; and use foo_t * in an interface, you must always expose the implementation struct foo since you cannot typedef twice. With struct foo * you have no such problems since you can use forward declarations. Now, either you will implicitly create rules about type exposure, need to have two sets of prototypes, some #ifdef magic, or you will have inconsitency in code (interface has struct foo*, code uses foo_t and foo_t *). This is *especially* problematic if you want to provide an interface which takes foo_t *, but cannot include the headers which provide the type due to collisions. Now you have a mismatch between the caller and the callee. See *for example* sys/rump/include/rump/rump.h for a few examples of current lossage with useless_t. In addition to the #ifdef crap at the top, notice how struct lwp interfaces take struct lwp * instead of lwp_t * and remember what I said above about silly_t *reducing* consistency. If there was no ridiculous_t, there would be no problem. Only if struct foo is never ever a part of any public interface, this does not apply. Even then I'd say that foo_t obfuscates, but that *is* a matter of personal preference and I don't care enough to argue about it. Still, it is difficult to know that 100 years from now we don't want struct foo in an interface. Hopefully that was clear and verbose enough.
You must expose the struct tag name, but there's no need to expose the
struct itself. This is not because you can't typedef twice but rather
because you can't use foo_t without defining it, and the incomplete
struct is not interface-compatible with the complete struct unless the
struct tags are the same.
This works fine (I've done it often enough):
foo.h:
struct foo;
typedef struct foo foo_t;
void foo_something(foo_t *, int);
foo.c:
#include "foo.h" /* or <foo.h> */
struct foo {
...
};
I don't see any such. What I see there are problems with trying to use
interfaces _without_ including the files exporting the interface
definitions in question, which is bound to have problems no matter what
So? That's because there's no "typedef struct lwp lwp_t;" line. I
can't see why not; because of the edict against including the proper
definition file, there's no reason not to typedef it alongside the
I still can't see the typedefs as being the problem. The problem I see
is an attempt to use interfaces without including the files declaring
the relevant types. That this breaks less visibly when using struct
tags strikes me as a reason to use foo_t, to render the bustification
blatant, rather than the converse.
"Then there's no hope of this working off NetBSD" is not an excuse to
avoid including the interface definitions. Rather, it's a reason to
build an include-file glue layer, or an include-file link farm, some
such, so you can get the interface from wherever it needs to come from
for the environment you're trying to build in. Perhaps on the next
If there were no types, there would be no problem. (BLISS, anyone?)
When you have a symptom and you find something that, if different,
would make the symptom go away, it does not necessarily follow that you
have found the problem. Say it's summer, and I'm uncomfortably hot;
perhaps the problem is not that my city is too far south but instead is
this overcoat I'm wearing.
/~\ The ASCII Mouse
\ / ...With all respect, this is not true. The following pattern works well.
1) You put "typedef struct foo foo_t;" in a header file named
"foo_type.h", and #include that in every header file where you want
foo_t to be used as a forward type (i.e., where you need to use foo_t *).
2) Then in the header file ("foo.h") where you define the contents of
struct foo, you also #include "foo_type.h" before you define the contents.
(MCCI actually uses slightly different names, and we of course group
all the forward structures for a single API into a "{module}_types.h"
header file; but this illustrates the idea.)
Files that include "foo_type.h" (including the header files that
define prototypes) don't see the implementation unless they include
"foo.h" explicitly.
This works well. It's portable to every C compiler I've come across
(dozens, and not just GCC). Compile speeds are not noticeably
affected -- our products that use this technique already have roughly
a thousand header files (for other reasons) and this has caused problems.
This technique has the additional advantage of hiding struct/union
decisions from all the modules except the modules that have the
implementation in-scope. (Otherwise, everyone who wants a pointer
has to know whether it's struct foo or union foo that's wanted.) We
have found this to be very convenient.
Best regards,
--Terry
This is untrue. There is no requirement to expose the contents of a FILE * for instance in order for API's to use it as an opaque data structure. On the pieces that actually need internals need the implementation exposed. James
Actually that is the one you must not do ... Since you can't then define 'const x *' etc. But I agree that most code shouldn't be dependant on the offsets of the majority of the members of most functions, and definitely not on the size of such structures. For example the contents of 'struct proc' and 'struct lwp' should not be exposed to any driver code, just to some parts of kern. Possibly you have a sub-structure which is exposed, and can grow, that contains fields that are commonly needed. David -- David Laight: david@l8s.co.uk
That is not a benefit. What does it buy you? Absolutely nothing. What does it cost you? A lot of clarity. It invites memory leaks, refcount bugs, accidental sharing of things you meant to have your own copy of, sometimes accidental copying of things you meant to share, and worse, all because you're wilfully and gratuitously blurring the distinction between a value and a pointer to a value. If you want to think in Java it's your lookout but please don't force it down everyone else's throat. -- David A. Holland dholland@netbsd.org
It can be. In particular, it encourages you to use the API, rather than trying to outsmart it. If you are quite sure whether x_t is a pointer or not, you may take steps based on your expectations of how to manage pointers (or non-pointers). This can be an advantage, especially for other people who may need to update an API you were supposed to be using... -s
On Tue, Aug 11, 2009 at 02:18:47AM -0500, Peter Seebach wrote: >> That is not a benefit. > > It can be. > > In particular, it encourages you to use the API, rather than trying to > outsmart it. If the public header for the API declares the structure in question, but does not define it, as should be the case for anything calling itself an opaque type, it's sufficient to write struct thingy; /* Opaque. */ and dressing it up any further just obscures what's really going on. > If you are quite sure whether x_t is a pointer or not, you may > take steps based on your expectations of how to manage pointers (or > non-pointers). This can be an advantage, especially for other people who > may need to update an API you were supposed to be using... If you don't know whether it's a pointer, you can't use it correctly, except in a very limited set of cases for very simple APIs. You get bitten by both memory management and sharing. Consider: silly_t foo, bar; foo = get_silly_thing(); bar = foo; change_silly_stuff(foo); /* Ok, at this point, has bar been changed? Guess away. */ /* And for that matter, is bar even valid any more? */ If you're coding in Haskell, where nothing is mutable and everything is garbage-collected, you can genuinely do without this distinction. But most people don't want to code in Haskell. -- David A. Holland dholland@netbsd.org
Let's say we commit to you that, definitely, silly_t is a pointer. Do you now know, without checking the API docs, whether or not bar is valid? Well, uhm. No. (And if the function is a function-like macro, you don't even know that foo and bar are still equal.) Okay, but what if we say that, for sure, silly_t is not a pointer, but an opaque non-pointer object. Now do you know? ... Well, actually, you still don't know, because it could be that silly_t is a structure CONTAINING at least one pointer. In which case bar might well now contain an invalid pointer, or a pointer to an obsolete object, or... well, we just don't know. So in short, if types can be opaque, you have already lost. -s
On Tue, Aug 11, 2009 at 03:10:11AM -0500, Peter Seebach wrote: > In message <20090811074826.GA16058@netbsd.org>, David Holland writes: >> If you don't know whether it's a pointer, you can't use it correctly, >> except in a very limited set of cases for very simple APIs. You get >> bitten by both memory management and sharing. > > True. Zackly :-) >> Consider: >> >> silly_t foo, bar; >> >> foo = get_silly_thing(); >> bar = foo; >> change_silly_stuff(foo); >> /* Ok, at this point, has bar been changed? Guess away. */ >> /* And for that matter, is bar even valid any more? */ > > Let's say we commit to you that, definitely, silly_t is a pointer. > > Do you now know, without checking the API docs, whether or not bar is > valid? Well, uhm. No. No, but if you know it's a pointer you'll go check, and ideally the API will be designed so the name and circumstances of the call tell you. E.g. after "silly_destroy(foo)" or "foo = munge_silly_tree(foo)" you'd reasonably expect that bar would no longer be valid, but after "if (is_silly_ok(foo))" you'd expect the converse. This is why it's generally a bad idea to write functions that consume references unless they're participating in a naming convention that makes it clear what's going on. Meanwhile, if you've been persuaded that silly_t is a plain value, because you copied it obviously bar is (1) independent of foo and (2) still valid. Which is fine if it really is... but if it's really a pointer, (1) is certainly false and (2) may be or become false without much warning, and then you end up in the weeds. > (And if the function is a function-like macro, > you don't even know that foo and bar are still equal.) That's why macros of that kind are eeevil. > Okay, but what if we say that, for sure, silly_t is not a pointer, but an > opaque non-pointer object. Now do you know? ... Well, actually, you still > don't know, because it could be that silly_t is a structure ...
Ahh, yes. ... Nonetheless, it's possible to have a non-pointer that has the same type management issues as a pointer. :) -s
On Tue, 11 Aug 2009 06:45:11 +0000 I agree, I see the benefit of exposing public structures of an API as typedefs, but it isn't good practice to me to hide the pointer inside, unless the name specifically contains addr or ptr in it (and I've seen cases where *addr_t typedefs were long, uint32_t or the like instead of a pointer, so addr is still not obvious)... -- Matt
Yes. But that benefit can be obtained in other, arguably, better ways.
In particular, incomplete structs enforce API use, without hiding what
is and isn't a pointer (which is the thing I most dislike about the _t
paradigm as outlined upthread).
To pick on sys/proc.h as a possibly-inappropriate example, this
paradigm has sys/proc.h containing
struct proc;
...API declarations...
and then something else - perhaps a .c file if there's just one, or if
not then sys/proc-impl.h or some such - includes sys/proc.h and adds
struct proc {
...details, private to the implementation...
};
But this depends on having a well-defined API in the first place, and
that is something that is woefully lacking in most of the kernel. I'd
put effort into creating well-defined APIs at all before worrying about
how to encourage/enforce use of them. (Actually, it's not quite that
bad; there are some moderately well-defined APIs in the kernel, such as
the whole bus-space infrastructure. But there are a lot of cases,
mostly historical from what I've seen, where the "API" is ill-defined
and consists of a struct which is exposed to a whole lot of code.)
/~\ The ASCII Mouse
\ / Ribbon Campaign
X Against HTML mouse@rodents-montreal.org
/ \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
On Tue, Aug 11, 2009 at 03:38:40AM -0400, der Mouse wrote: > But this depends on having a well-defined API in the first place, and > that is something that is woefully lacking in most of the kernel. I'm working on it! -- David A. Holland dholland@netbsd.org
If anything like this is done, I'd like to kindly request that there be an option to expose the contents of the structure with a config or compile flag. It is very annoying to try to debug a program where you can't print out a structure unless you're in the "right" stack frame. eric
On Tue, Aug 11, 2009 at 12:42:33PM -0500, Eric Haszlakiewicz wrote:
> > struct proc {
> > ...details, private to the implementation...
> > };
>
> If anything like this is done, I'd like to kindly request that
> there be an option to expose the contents of the structure with a
> config or compile flag. It is very annoying to try to debug a
> program where you can't print out a structure unless you're in
> the "right" stack frame.
gdb is usually pretty good about this, IME. If ddb needs fixing, let's
fix it.
--
David A. Holland
dholland@netbsd.org
I *was* using gdb, but maybe it was due to it being an old version. argh, and now gdb just hangs when I try to debug anything so I can't try it out. something must be messed up with my machine. :( eric
On Wed, Aug 12, 2009 at 11:42:07AM -0500, Eric Haszlakiewicz wrote:
> > > > struct proc {
> > > > ...details, private to the implementation...
> > > > };
> > >
> > > If anything like this is done, I'd like to kindly request that
> > > there be an option to expose the contents of the structure with a
> > > config or compile flag. It is very annoying to try to debug a
> > > program where you can't print out a structure unless you're in
> > > the "right" stack frame.
> >
> > gdb is usually pretty good about this, IME. If ddb needs fixing, let's
> > fix it.
>
> I *was* using gdb, but maybe it was due to it being an old version.
It's been a long while since I noticed this problem, and given my
general coding practices I think I'd trip on it regularly. I haven't
had any problem looking inside the opaque structs in the code I've
been working on recently, anyhow.
> argh, and now gdb just hangs when I try to debug anything so I can't
> try it out. something must be messed up with my machine. :(
Not necessarily. It's probably PR 40594, and note that there's a
workaround.
--
David A. Holland
dholland@netbsd.org
ah, yes that appears to be my hanging problem. Thanks! I guess you're right about gdb working. The case I ran into before where it wasn't was where I was compiling my program with debugging turned on, but the library that actually had the structure definition in it wasn't compiled with -g, so I suppose gdb didn't have anywhere to get the actual structure definition from. Obviously, that case can't happen when debugging a kernel (unless modules are involved). eric
Salut, Apart from this question, which I don't think I will comment on, I recently encountered a problem extending an api_t and have a question: - bla_t contains a list of references to blubb_t - blubb_t contains a pointer back to bla_t How would that ever work? Tonnerre
Oh, you can work that something like this
typedef struct bla bla_t;
typedef struct bla * blaptr_t;
typedef struct blubb blubb_t;
typedef struct blubb * blubbptr_t;
struct bla {
blubb_t blubb;
blubb_t * blubbptr1;
blubbptr_t blubbptr2;
bla_t * blaptr1;
blaptr_t blaptr2;
};
struct blubb {
bla_t bla;
bla_t * blaptr1;
blaptr_t blaptr2;
blubb_t * blubbptr1;
blubbptr_t blubbptr2;
};
is that what you meant?
iain
Salut,
I mean:
typedef struct {
...
blubb_t blubbs[MAX_BLUBBS];
...
} bla_t;
typedef struct {
...
bla_t owner;
...
} blubb_t;
Tonnerre
Typedefs have nothing to do with that. You cannot create structures like this in C since in this setup you need to know the size which you can't define up front. James
Salut, Sorry, I forgot an asterisk; of course I meant bla_t *owner; Anything else would be pointless. If you want to do that with typedefs, you have to use the names of the structs, which contradicts the idea that you don't need to know what's behind the type. Thus, typedefs should be considered as having defunct reasoning in favor of them while bringing disadvantages for both readability and understandability. Tonnerre
As James said, you can't do exactly that as two structures cannot fully
contain each other (mumble .. laws of physics :).. but your original
So, you just need to declare the structure name first and define the
structure content afterwards which requires a structure tag:
typedef struct bla bla_t;
typedef struct blubb blubb_t;
struct bla {
...
blubb_t blubbs[MAX_BLUBBS]; /* array of blubbs */
...
blubb_t *pblubs[MAX_BLUBBS]; /* array of pointers */
...
};
struct blubb {
...
bla_t *owner; /* pointer to bla is ok */
...
};
you are not obliged to use "blubb" and "bla" again and the structure
namespace is separate so it won't collide with anything else.
or if you wanted only pointers you could typedef the pointer:
typedef struct bla * bla_t;
typedef struct blubb * blubb_t;
struct bla {
...
blubb_t blubbs[MAX_BLUBBS]; /* array of pointers */
...
};
struct blubb {
...
bla_t owner; /* pointer to bla */
...
};
but as noted elsewhere that is flirting with obfustication (which may be
the intention in an interface that provides a 'cookie')
iain
Do you mean "how could you declare such a thing?"
/* in bla.h */
typedef struct bla bla_t;
#define BLUBBS_PER_BLA 8
/* in blubb.h */
typedef struct blubb blubb_t;
/* in bla-private.h */
#incude "bla.h"
#incude "blubb.h"
struct bla {
blubb_t * blubblist[BLUBBS_PER_BLA];
}
/* in blubb-private.h */
#incude "bla.h"
#incude "blubb.h"
struct blubb {
bla_t * blaptr;
}
--apb (Alan Barrett)
Salut, I wouldn't want to name the structs, that would be against the idea of having a typedef, right? Tonnerre
On Tue, Jun 16, 2009 at 10:19:06AM +0100, Mindaugas Rasiukevicius wrote: > > > I would like to typedef and replace the struct usage in UVM, so that > > > struct vm_map would become vm_map_t, struct vm_anon - vm_anon_t, and so > > > on. <...> > > Just to make this clear, I do not want to typedef structs as pointers. > I agree that it is confusing (although it has a good rationale for some > cases, eg. when structure size is dynamic). I'm not convinced, but that's a different argument :-) > > 1) obfuscates code. there is no reason to tell if silly_t is an int, > > struct or pointer to something just by looking at the type > > I am not sure what do you mean. Each typedef, eg. vm_page_t would be a > structure, where vm_page_t * a pointer to it. No intention to typedef > non-structures in UVM. Historically, *_t types are primitive types, which means essentially integers. Some exceptions that currently exist (e.g. in the pthreads API and some inappropriate typedefs of pointers in the kernel) are bugs. Historically also structures are always used as "struct foo"; but preserving this convention is not as important as not treading on other related conventions. So, if we want to do this, which I don't have a strong opinion about, can we use some naming convention other than _t? My suggestion would be to just do typedef struct vm_page vm_page; and leave it at that. -- David A. Holland dholland@netbsd.org
No, not really, especially not in C generally (perhaps in Unix, but there are perhaps other explanations for why Unix code failed to use Well, maybe, if you go back in time so far that "typedef" didn't exist. Of course if you go back that far you'll find even header include files were poorly used (in Unix code, that is) and full "struct" definitions I really strongly disagree with the idea of not using "_t" for typedef names. Historically the real reason for appending "_t" to typedef names is to mark the identifier as being a "type" -- i.e. it's a special identifier that exists in a unique namespace. This is useful for _all_ types of syntax highlighting, including that done implicitly by the human eye and brain. In your example "vm_page" is by default a variable name to me, not a type name. The use of the "_t" suffix on typedef names is an incredibly important idiom that should be used everywhere possible. FWIW, I do also disagree with including the "*" pointer qualifier in the typedef unless the name somehow reflects this fact, such as fooptr_t, foop_t, foo_p_t, or foo_pt, or something like that (so long as it's consistent, especially with existing code, from anywhere, if indeed there's anything already statistically consistent, which would in my experience be the "fooptr_t" form). --=20 Greg A. Woods Planix, Inc. <woods@planix.com> +1 416 218-0099 http://www.planix.com/
On Fri, Jun 19, 2009 at 01:51:27PM -0400, Greg A. Woods wrote:
> > Historically, *_t types are primitive types
>
> No, not really, especially not in C generally (perhaps in Unix, but
> there are perhaps other explanations for why Unix code failed to use
> this powerful idiom as uniformly as it should have).
Historically in Unix, though, which is the point.
> > Historically also structures are always used as "struct foo"; but
> > preserving this convention is not as important as not treading on
> > other related conventions.
>
> Well, maybe, if you go back in time so far that "typedef" didn't exist.
Again, historically in Unix.
> > So, if we want to do this, which I don't have a strong opinion about,
> > can we use some naming convention other than _t?
>
> I really strongly disagree with the idea of not using "_t" for typedef
> names.
>
> Historically the real reason for appending "_t" to typedef names is to
> mark the identifier as being a "type" -- i.e. it's a special identifier
> that exists in a unique namespace.
Yes, it is a type, but it is a *primitive* type. Non-primitive types
have been, historically, marked with 'struct' or 'union', and the
desire to retain this visual distinction is why Unix code does not do
the "typedef struct { ... } foo" idiom that much other C code does.
Structs and particularly pointers are not used the same way (no matter
how abstract they are!) and should be tagged, if tagged, with
something other than _t.
Myself, I don't see any great need to tag them, as the distinction
between types and values is abundantly clear from syntax, but I don't
have anywhere near such a strong opinion about that.
--
David A. Holland
dholland@netbsd.org
Historically in Unix it doesn't matter though -- Unix had too much baggage carried forward from the days before the invention of "typedef". I'd guess dmr might even agree with me and also close by saying "practice what I preach, not what I do". Just because Unix has/had poor programming practises as extra baggage doesn't mean NetBSD needs to carry it all, or even some, forward as well. Well, yes, up to the point where "typedef" came into being at least. Since then "typedef" offers a way to name any kind of type, primitive or otherwise. Perhaps historically the only really good reason to ever use "typedef" for primitive types where where they might have to change size within the same class of primitive type for some variant implementation such as to mask underlying hardware differences, or to support scaling, etc. However the reasons for using "typedef" to alias struct or union definitions are far more numerous and perhaps more vaporous as well, but now those reasons are generally accepted they apply to primitive data The point with "_t" is to distinguish the type alias name as being a typedef name, not in how the underlying data structure is used regardless of whether it is a pointer, struct, or union. Use of "_t" for all typedef names is a convention that helps both human and computer distinguish the unique properties of these unique identifiers. They are not labels on storage (text or data) they are labels on language constructs and as such it is critically important that they be treated I certainly don't agree at all with the use of "abundantly" there. Indeed the tagging of typdef names is not necessary for the compiler, but neither is the use of meaningful nouns in identifiers (instead of just creating them from random alphabetic sequences for example) -- I'm not talking about syntax, I'm talking about human factors and non-compiler partial parsers used to support human factors (such as syntax highlighters, etc.) --=20 Greg A. ...
On Fri, Jun 19, 2009 at 02:57:14PM -0400, Greg A. Woods wrote: > > > > Historically, *_t types are primitive types > > > > > > No, not really, especially not in C generally (perhaps in Unix, but > > > there are perhaps other explanations for why Unix code failed to use > > > this powerful idiom as uniformly as it should have). > > > > Historically in Unix, though, which is the point. > > Historically in Unix it doesn't matter though -- Unix had too much > baggage carried forward from the days before the invention of "typedef". Yes, and that baggage was kept precisely because of the distinctions I've cited. > > > Historically the real reason for appending "_t" to typedef names is to > > > mark the identifier as being a "type" -- i.e. it's a special identifier > > > that exists in a unique namespace. > > > > Yes, it is a type, but it is a *primitive* type. Non-primitive types > > have been, historically, marked with 'struct' or 'union', and the > > Well, yes, up to the point where "typedef" came into being at least. > > Since then "typedef" offers a way to name any kind of type, primitive or > otherwise. You are talking about what is possible; I am talking about historic practice in the kernel and the ... more important parts of userland. > > Structs and particularly pointers are not used the same way (no matter > > how abstract they are!) and should be tagged, if tagged, with > > something other than _t. > > The point with "_t" is to distinguish the type alias name as being a > typedef name, not in how the underlying data structure is used > regardless of whether it is a pointer, struct, or union. This is entirely pointless. > Use of "_t" > for all typedef names is a convention that helps both human Not likely. Or do you also advocate full Hungarian notation? > and computer Bollocks. > distinguish the unique properties of these unique identifiers. They are > not labels on storage (text or data) they are ...
FWIW, in Plan9 for example, a complex, composed type is lexically
identified by a first capital letter ; while primitive types are all
lower case.
So:
typedef struct Tm {} Tm;
This is IMHO sound, since complex, composite type are special,
extensions of the language in some sense.
--
tHIerry Laronde (Alceste) <tlaronde +AT+ polynum +dot+ com>
http://www.kergis.com/
Key fingerprint = 0FF7 E906 FBAF FE95 FD89 250D 52B1 AE95 6006 F40C
I can explain why the code is the way it is: Before I wrote the UVM code, I spent alot of time studying other VM code. I found that having these kinds of typedefs for structures made the code harder to read (because you don't know if you are dealing with a structure, or a pointer to a structure --- folks do it both ways). So when I wrote UVM I attempted to remove as much of this ambiguity as possible. I think the "struct"'s and "*"'s are useful semantic cues that make it easier for new folks to understand the code. If we feel typedef structs are important, I would be in favor of some sort of hungarian notation for the type names, so the semantic information is not lost (e.g. struct vs struct *). But is it worth the effort to do that? chuck
On Wed, Jul 22, 2009 at 04:39:54PM +0000, Chuck Cranor wrote: > I can explain why the code is the way it is: > > Before I wrote the UVM code, I spent alot of time studying other VM > code. I found that having these kinds of typedefs for structures > made the code harder to read (because you don't know if you are dealing > with a structure, or a pointer to a structure --- folks do it both ways). > So when I wrote UVM I attempted to remove as much of this ambiguity as > possible. I think the "struct"'s and "*"'s are useful semantic cues > that make it easier for new folks to understand the code. This is what I've been saying also, but I haven't been getting much traction. :-| -- David A. Holland dholland@netbsd.org
If the APIs are designed well, you: 1- Won't be dealing with structs directly, only through accessors / mutators (ABI stability). 2- Won't have to know / care what underlying type you're dealing with anyway. If we ever want to have a chance of supporting a modular kernel really well, then we need to have better ABI stability in our kernel, which -- thorpej
