Reputation: 2147
I'm trying to create an API that is easy to use correctly and hard to use incorrectly.
Imagine you had a function "bool MyObject_SetLocalDateTime(MyObject *pMyObject, params...)"
which allows client to set date and time in YYYY MM DD HH MM SS
format:
MyObject *pMyObject = MyObject_Create();
...
MyObject_SetLocalDateTime(pMyObject, params...);
...
MyObject_Destroy(&pMyObject);
What would be a good interface for the function? I'd appreciate any tips on how to make interfaces easy to use correctly and hard to use incorrectly in ANSI C (not in C++).
Upvotes: 1
Views: 584
Reputation: 906
I would first say decide what "correctly" is. Seriously.
Do you want the inputs to be the most accurate? Do you want the function to not fail? Do you want to limit the value of what can be input? You probably want to consider the requirements for what you are creating.
If at the point this function is called, what format is the data in? It might just be in a string which the user entered of "YYYY MM DD HH MM SS", then maybe it would be wisest to take one single string and parse out the values yourself. Of course, that is alot more work inside your function.
Also, if you are writing the function for yourself, you can be more lenient on input values and testing, because you probably know what is expected. If you are creating a function for an operating system which will have hundreds of thousands of people using those API's you'll need to be more explicit with what is allowed and test for them inside your function.
Depending on what is most "correct" for your situation, there are a number of ways to specify even the simple function you reference.
bool MyObject_SetLocalDateTime(pMyObject, int YYYY, unsigned int MM, unsigned int DD, int HH, int MM, int SS); // return value indicates success or failure.
But, what if the consumer passes in a zero for the MM ? What if the consumer passes in 13? Do you use base-0 (which is usually what C uses) or a regular 1-12 for the number referring to the month (jan-dec), which would make more sense from a human month perspective, but is sort of strange to the way C programmers think?
For something like date and time, the C library has definitions for this, which would make it easier for you. Also, because the C library is already doing it that way, it might seem more natural to other users who are using your function.
You also need to define what you mean by "hard to use incorrectly". Again, I am being serious. Maybe you would want to create an enum for the months (and days), and pass that in instead of an int. This would give the API additional type checking by the compiler, but a clever consumer of your API might caste to another value, so don't think you can skip testing for valid input.
Inside your function you'll want to validate the input values, no matter what form they are passed in, to make sure they are valid, checking that you do not allow a day of 30 for Feb, and you do allow 29 for feb but only every four years. Dates and times have alot of hidden complexity, which makes it wise to rely on routines already developed in the OS, or runtime libraries.
Upvotes: 2
Reputation: 3297
In C
, i would follow the following rules :
use struct const* struct_param
so mutable input/output params so that their pointer values could not be changed inside that API .
use struct const * const structParam
for immutable input param so that their pointer value and contents can not be changed inside that API.
In C++ use references instead of pointers, i mean, C++ explicitly provides passing by reference so you can reduce passing by value of pointers.
Upvotes: 0
Reputation: 1889
You can give a hint in the name: MyObject_SetLocalDateTime_YMDHMS
Upvotes: 0
Reputation: 74345
Why wouldn't you simply use time_t
and/or struct tm
?
Something like the following would do just fine:
time_t my_local_time ;
MyObject_SetLocalDateTime(pMyObject, my_local_time ) ;
or
struct tm my_local_time ;
MyObject_SetLocalDateTime(pMyObject, my_local_time ) ;
Upvotes: 1