S
Seebs
So, watching the typedef battles, something has become clear to me.
Engineers suck at communicating.
Underneath it all, it is perhaps useful to remember that most of the
active participants here are people who have successfully written reasonably
large programs in C, so however they're thinking about C inside their heads,
it *works*. Maybe it's not exactly correct, but at the bare minimum, you
can be reasonably confident that it's a good enough model to have both
explanatory and predictive power for the behavior of programs on real
machines.
One of the most useful non-engineering skills I've ever applied to engineering
is learning to communicate better. Interestingly, writing clearly, while
certainly useful, is by far the lesser part of this. The big thing is to
learn to listen better. And I still have a long way to go on that.
A friend of mine gave me an excellent summary of a useful tactic when someone
who is otherwise apparently pretty rational or well-informed says something
obviously false:
Rather than thinking of it as false, think of it as true, and try
to figure out what it could be true *of*.
That's certainly contrary to the way engineers usually think! However, it's
very useful.
Here's an example of how I might apply that. It is obvious to me that size_t
is distinct from any of the standard unsigned integer types. Someone comes
along and tells me that size_t is the same as one of those types. Obviously
this is untrue... But wait! He's no idiot. What's he talking about?
Well, it turns out, what he's saying is quite true if, instead of talking
about the abstract language spec, I talk about any real implementation I've
ever heard of. On any real implementation I've seen, size_t is the same
type as one of unsigned short, unsigned int, unsigned long, or unsigned long
long. I've never heard of an exception. So actually, he's saying something
true, but he's talking about something other than what I'm talking about. If
I understand this, I can get somewhere. If I don't, I'm going to spend a
lot of time telling him that he's wrong, which he's not going to believe,
because he's tested his claim and it's obviously true.
Once we've got that figured out, we can potentially have a productive
discussion about whether it's more useful or effective to think about types
in terms of logical types or in terms of the compatibility rules that
are invoked when you try to assign a 'foo *' to a 'bar *'. Both ways of
thinking about types work. You can write large programs thinking about
it either way. Furthermore, each way of thinking about types will expose
you to some problems -- which the other avoids.
The same thing comes up when, say, someone talks about "the stack". All
the experienced C programmers know that C doesn't have a stack, except the
ones who know that C does have a stack. There are at least three reasonably
plausible ways of thinking about this. You can treat it as a contiguous
block of memory which always grows in the same direction. Sure, it's not
exactly right, but it'll work well enough most of the time, and it's simple.
You can treat it as totally separate activation records. You can think of
it more like a LIFO queue, without any regard to how it goes together.
All of these models *work*. None of them are exactly mandated. If, instead
of calling people "wrong" when they use a different model, you try to
understand the model they're using and see how it could be useful to you,
you're more likely to learn something.
Learning to distinguish between the thing you're modeling, and your model
of it, is really useful. It can make you a better programmer. It can
also reduce, dramatically, the number of clueless jerks you encounter on
Usenet.
-s
Engineers suck at communicating.
Underneath it all, it is perhaps useful to remember that most of the
active participants here are people who have successfully written reasonably
large programs in C, so however they're thinking about C inside their heads,
it *works*. Maybe it's not exactly correct, but at the bare minimum, you
can be reasonably confident that it's a good enough model to have both
explanatory and predictive power for the behavior of programs on real
machines.
One of the most useful non-engineering skills I've ever applied to engineering
is learning to communicate better. Interestingly, writing clearly, while
certainly useful, is by far the lesser part of this. The big thing is to
learn to listen better. And I still have a long way to go on that.
A friend of mine gave me an excellent summary of a useful tactic when someone
who is otherwise apparently pretty rational or well-informed says something
obviously false:
Rather than thinking of it as false, think of it as true, and try
to figure out what it could be true *of*.
That's certainly contrary to the way engineers usually think! However, it's
very useful.
Here's an example of how I might apply that. It is obvious to me that size_t
is distinct from any of the standard unsigned integer types. Someone comes
along and tells me that size_t is the same as one of those types. Obviously
this is untrue... But wait! He's no idiot. What's he talking about?
Well, it turns out, what he's saying is quite true if, instead of talking
about the abstract language spec, I talk about any real implementation I've
ever heard of. On any real implementation I've seen, size_t is the same
type as one of unsigned short, unsigned int, unsigned long, or unsigned long
long. I've never heard of an exception. So actually, he's saying something
true, but he's talking about something other than what I'm talking about. If
I understand this, I can get somewhere. If I don't, I'm going to spend a
lot of time telling him that he's wrong, which he's not going to believe,
because he's tested his claim and it's obviously true.
Once we've got that figured out, we can potentially have a productive
discussion about whether it's more useful or effective to think about types
in terms of logical types or in terms of the compatibility rules that
are invoked when you try to assign a 'foo *' to a 'bar *'. Both ways of
thinking about types work. You can write large programs thinking about
it either way. Furthermore, each way of thinking about types will expose
you to some problems -- which the other avoids.
The same thing comes up when, say, someone talks about "the stack". All
the experienced C programmers know that C doesn't have a stack, except the
ones who know that C does have a stack. There are at least three reasonably
plausible ways of thinking about this. You can treat it as a contiguous
block of memory which always grows in the same direction. Sure, it's not
exactly right, but it'll work well enough most of the time, and it's simple.
You can treat it as totally separate activation records. You can think of
it more like a LIFO queue, without any regard to how it goes together.
All of these models *work*. None of them are exactly mandated. If, instead
of calling people "wrong" when they use a different model, you try to
understand the model they're using and see how it could be useful to you,
you're more likely to learn something.
Learning to distinguish between the thing you're modeling, and your model
of it, is really useful. It can make you a better programmer. It can
also reduce, dramatically, the number of clueless jerks you encounter on
Usenet.
-s