F
Francis Johnson
I've been having a discussion with some folks here about the wisdom or
otherwise of "building extensibility into an API".
Consider your favorite function in one of your libraries, perhaps
void foo(int bar, char *baz);
Now maybe you think of some cool improvement to foo that you could make,
but this relies on being able to pass an additional parameter to foo.
You now have some unattractive choices:
1) change the signature of foo and break API compatability between
versions of the library
2) have a new function
foo_v2(int bar, char *baz, long double newparam);
and make foo a wrapper for foo_v2.
3) don't make the improvement.
Now, this dilemma would never have arisen if you'd "built extensibility
into the API" in the following way.
Each function you write takes an unused void * parameter. So foo starts
out as
void foo(int bar, char *baz, void *p);
and the last parameter should be NULL.
Now, consider extending the parameters of foo. You now use a
foo_v2_extra_params structure. Its first field encodes the additional
parameters, and the remaining fields are these parameters. Then version
2 of foo can do this:
void foo(int bar, char *baz, void *p)
{
/* define additional params as auto variables */
if(p)
/* process *p, set up extra args */
else
/* set additional params to defaults */
/* do stuff */
}
If foo improves again, the struct just gets enlarged, and the function
casts p appropriately before proceeding.
Have people here implemented something like this in the past? What do
you think of it as a solution to the "API extension" problem?
otherwise of "building extensibility into an API".
Consider your favorite function in one of your libraries, perhaps
void foo(int bar, char *baz);
Now maybe you think of some cool improvement to foo that you could make,
but this relies on being able to pass an additional parameter to foo.
You now have some unattractive choices:
1) change the signature of foo and break API compatability between
versions of the library
2) have a new function
foo_v2(int bar, char *baz, long double newparam);
and make foo a wrapper for foo_v2.
3) don't make the improvement.
Now, this dilemma would never have arisen if you'd "built extensibility
into the API" in the following way.
Each function you write takes an unused void * parameter. So foo starts
out as
void foo(int bar, char *baz, void *p);
and the last parameter should be NULL.
Now, consider extending the parameters of foo. You now use a
foo_v2_extra_params structure. Its first field encodes the additional
parameters, and the remaining fields are these parameters. Then version
2 of foo can do this:
void foo(int bar, char *baz, void *p)
{
/* define additional params as auto variables */
if(p)
/* process *p, set up extra args */
else
/* set additional params to defaults */
/* do stuff */
}
If foo improves again, the struct just gets enlarged, and the function
casts p appropriately before proceeding.
Have people here implemented something like this in the past? What do
you think of it as a solution to the "API extension" problem?