tags:

views:

119

answers:

8

Quoting a code snippet :

/**
 * list_add - add a new entry

 * @new: new entry to be added
 * @head: list head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */

static inline void list_add(struct list_head *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}

I have seen similar code in several different programs, especially those manipulating data structures. What is the usual intention in adding this extra level of indirection - why can't the code inside __list_add be put inside list_add ?

A: 

It can.

However, there are probably other public entries that can share the code in __list_add(). eg, there may be a push() or an insert_head() or something like that.

NOTE: If this is C++ then you might want to rethink calling your variables new, as this is a reserved word.

rikh
This is apparently not C++, see the struct qualifier, completely redundant in C++.
EFraim
+2  A: 

It's about code reuse, and avoiding duplication.

__list_add() contains code that is useful in more situations than just this one, and can be shared between several different functions.

Sharing code like this has several advantages:

  • If there's a bug in __list_add() and you fix it, all the functions that use it get the fix.
  • If __list_add() gets an enhancement (eg. you make it faster) all the functions get faster.
  • There's only one place to look when you want to see how items are added to lists.
RichieHindle
A: 

__list_add will be intended as a "private" internal function which might have multiple uses internally. The public facing list_add is there as a convenient wrapper around it.

Paul Dixon
+3  A: 

If you copy code, it will make maintenance harder. In this example, the extra level of indirection hides the parameter next. It will provide a function with just 2 parameters rather than 3.

If the code inside the __list_add() is copied, it needs to be copied to multiple places. If then the list mechanism is changed somewhat, all of these places need to be updated too, or bugs will start to pop-up (i.e. a FIFO and LIFO implementation of a list show different behavior).

There is always a tradeoff; another level of indirection also adds complexity and possibly overhead, as opposed to duplicating lines of code or having lots of parameters in the API.

Adriaan
+1 for spotting that list_add takes two and __list_add takes three parameters.
Frerich Raabe
A: 

This wrapper is inline. If you added the body of __List_add, that too would be inlined. The apaprent goal is to just inline the pushing of the extra head->next argument and nothing else.

MSalters
`inline` does not guarantee inlining.
EFraim
Indeed, but the lack of guarantees is not relevant here. And my response would become unreasonable long if I had to explain all details, such as how compilers could inline half of a function
MSalters
A: 

That function comes from the linux kernel. It belongs to the generic list implementation:

Take a look: __list_add()

__list_add() is used in many places: e.g. list_add() which adds an element at a list head, list_add_tail() which adds an element at list tail... It can also be used to insert an element at a given position.

Nicolas Viennot
A: 

It is also common to define an wrapper function for recursive functions so the initial parameters are set correctly.

See binary search on wikipedia for Recursion (computer science)

epatel
A: 

Could also be to keep binary compatibility. you have an indirection that allows to keep the ABI invariant.

From http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html

When a new version of a library is binary-incompatible with the old one the soname needs to change. In C, there are four basic reasons that a library would cease to be binary compatible:

  1. The behavior of a function changes so that it no longer meets its original specification,
  2. Exported data items change (exception: adding optional items to the ends of structures is okay, as long as those structures are only allocated within the library).
  3. An exported function is removed.
  4. The interface of an exported function changes.
Stefano Borini