tags:

views:

144

answers:

2

Is there any benefit in having never-defined structures in C ?

Example in SQLite source code :

/* struct sqlite3_stmt is never defined */
typedef struct sqlite3_stmt sqlite3_stmt;

And the object is manipulated like so :

typedef struct Vdbe Vdbe;
struct Vdbe {
    /* lots of members */
};


int sqlite3_step(sqlite3_stmt *pStmt) {
    Vdbe *v = (Vdbe*) pStmt;
    /* do stuff with v... */
}

So why not just use a usual abstract type, with the actual structure privately defined in foo.c source and a public typedef in foo.h header ?

+11  A: 

It is defined like this to hide the implementation detail of sqlite3_stmt from the user, thus avoiding the internal states from being messed around. See Opaque pointer.

(This also forces the user only to use the type as a pointer since the structure sqlite3_stmt itself has incomplete implementation.)


Edit: VDBE (virtual database engine) is just "a" back-end of the SQLite3 API. I believe the back-end is changeable, thus a sqlite3_stmt* is not necessarily a Vdbe*. Not exposing Vdbe* in the API because the back-end detail should not be exposed.

KennyTM
Still, in the Opaque pointer article's example, the `struct cat_t` is defined... Is `struct sqlite3_stmt` only used to hide the implementation on `struct Vdbe` ? Then, is there a reason not to use the Opaque pointer pattern on `Vdbe` ?
Axel
+1 "I believe the back-end is changeable" sounds like a very plausible reason!
Martin B
+5  A: 

To clarify: What you're asking is why SQLite does the above instead of doing this:

Header file:

typedef struct sqlite3_stmt sqlite3_stmt;

C file:

struct sqlite3_stmt {
    /* lots of members */
};


int sqlite3_step(sqlite3_stmt *pStmt) {
    /* do stuff with pStmt... */
}

(This is the canonical form of the "opaque pointer" pattern linked to in KennyTM's answer.)

The only good reason I can think of why SQLite does what it does is the following:

The backend code, I'm speculating, came before the API and used the name Vdbe -- the name probably means something related to the implementation along the lines of "virtual database entry" (guessing wildly here).

When time came to create the API, someone realized that the parameter required by sqlite3_step was a Vdbe but that this was not exactly a name that would convey a lot to the user of the API. Hence, from the user's point of view, a Vdbe is referred to as an sqlite3_stmt.

The point here, then, is to differentiate between two views of the same item: The backend thinks in terms of Vdbes (whatever they are) because that's a name that makes sense in the context of the implementation. The API talks about sqlite3_stmts because that's a name that makes sense in the context of the interface.

Edit: As Amarghosh points out, why not just do this to achieve the same effect?

typedef struct Vdbe sqlite3_stmt;

KennyTM points out a good possible reason (please vote him up, I don't want to siphon off his rep here): VDBE is only one of several possible backends; the interface uses a "generic" sqlite3_stmt, and this is then cast to whatever the backend uses to implement it.

Martin B
Then why don' they just `typedef struct Vdbe sqlite3_stmt;`
Amarghosh
You got it right, this is what I was asking. I like the idea of the two views of the same item. (and, by the way, it is my understanding of SQLite that VDBE stands for "virtual database engine")
Axel
@Amarghosh: Good point... KennyTM's edited answer provides a good possible reason (that VDBE is just one of several backends)
Martin B
@Martin that makes sense! You might want to incorporate that to your post too.
Amarghosh