simply good use of pointers-to-pointers etc. For example, I've seen too many people who delete a singly-linked list entry by keeping track of the "prev" entry, and then to delete the entry, doing something like
if (prev) prev->next = entry->next; else list_head = entry->next;
and whenever I see code like that, I just go "This person doesn't understand pointers". And it's sadly quite common.
People who understand pointers just use a "pointer to the entry pointer", and initialize that with the address of the list_head. And then as they traverse the list, they can remove the entry without using any conditionals, by just doing a "*pp = entry->next".
I'm going to have to disgree with Linus on that one. When I'm coding in a mixed group of people that includes old farts and interns and the performance isn't that critical, I'll do the former over the latter to insure that everyone in the group will understand it easily and will have less chance of breaking it if they change it. It can mean the difference between code that is robust and code that is fragile when it's being worked on, not just when it's running.
I believe that his pointer example is more a matter of personal style. I can easily see how doing away with the conditions will make for more efficient code, but in many cases, the preference he cites might also make the code a little more obfuscated. However, even that's nothing that a single-line comment wouldn't fix, making sure that whoever is reading the code fully realizes the intent behind it. I think perfectly valid arguments can be made for doing it either way.
I think perhaps the point that he was making about designing with pointers wasn't fully appreciated by everyone, because he didn't really spell it out. It's not just a matter of preferred coding style nor clarity, far from it.
The unconditional pointer update approach is atomic by virtue of the update being performed in a single memory write cycle, whereas the longer conditional form is clearly not atomic, and to make it atomic would require using locks. (There's a bit more to it than that because you still have to worry about what is being assigned, but it does reduce the scope of the problem significantly.)
This distinction is extremely important in a highly concurrent application like an operating system kernel, because you can merrily use his preferred code everywhere without worrying whether it's going to be used concurrently or only called within a protected critical region. In contrast, if the conditional form were used concurrently then you would have a wonderful recipe for intermittent concurrency bugs, the kernel designer's very worst nightmare.
You've actually made a good point... atomicity is actually a *VERY* good reason to not use the conditional form, but not every application requires that. It's certainly not generally going to be the case that atomicity is a requirement, and often when it is, it would might be more practical to use an explicit mutex on your data to ensure nothing else touches it while you're using it. Even when mutexes are not practical (and I know that can very easily be the case), however, and atomicity is still requir
The unconditional pointer update approach is by no means atomic unless you use memory barriers or atomic instructions. There is a reason C++11 added <atomic>.
A debugged program is one for which you have not yet found the conditions
that make it fail. -- Jerry Ogdin
Not So Fast On The Pointers (Score:4, Interesting)
simply good use of pointers-to-pointers etc. For example, I've seen too many people who delete a singly-linked list entry by keeping track of the "prev" entry, and then to delete the entry, doing something like
if (prev)
prev->next = entry->next;
else
list_head = entry->next;
and whenever I see code like that, I just go "This person doesn't understand pointers". And it's sadly quite common.
People who understand pointers just use a "pointer to the entry pointer", and initialize that with the address of the list_head. And then as they traverse the list, they can remove the entry without using any conditionals, by just doing a "*pp = entry->next".
I'm going to have to disgree with Linus on that one. When I'm coding in a mixed group of people that includes old farts and interns and the performance isn't that critical, I'll do the former over the latter to insure that everyone in the group will understand it easily and will have less chance of breaking it if they change it. It can mean the difference between code that is robust and code that is fragile when it's being worked on, not just when it's running.
Re: (Score:5, Interesting)
I believe that his pointer example is more a matter of personal style. I can easily see how doing away with the conditions will make for more efficient code, but in many cases, the preference he cites might also make the code a little more obfuscated. However, even that's nothing that a single-line comment wouldn't fix, making sure that whoever is reading the code fully realizes the intent behind it. I think perfectly valid arguments can be made for doing it either way.
Personally, I would classify thi
Key issue in kernels, atomicity (Score:2)
I think perhaps the point that he was making about designing with pointers wasn't fully appreciated by everyone, because he didn't really spell it out. It's not just a matter of preferred coding style nor clarity, far from it.
The unconditional pointer update approach is atomic by virtue of the update being performed in a single memory write cycle, whereas the longer conditional form is clearly not atomic, and to make it atomic would require using locks. (There's a bit more to it than that because you still have to worry about what is being assigned, but it does reduce the scope of the problem significantly.)
This distinction is extremely important in a highly concurrent application like an operating system kernel, because you can merrily use his preferred code everywhere without worrying whether it's going to be used concurrently or only called within a protected critical region. In contrast, if the conditional form were used concurrently then you would have a wonderful recipe for intermittent concurrency bugs, the kernel designer's very worst nightmare.
Re: (Score:2)
You've actually made a good point... atomicity is actually a *VERY* good reason to not use the conditional form, but not every application requires that. It's certainly not generally going to be the case that atomicity is a requirement, and often when it is, it would might be more practical to use an explicit mutex on your data to ensure nothing else touches it while you're using it. Even when mutexes are not practical (and I know that can very easily be the case), however, and atomicity is still requir
Re: (Score:2)
The unconditional pointer update approach is by no means atomic unless you use memory barriers or atomic instructions. There is a reason C++11 added <atomic>.