How to design (and do I want) an API?
-
Hi, I'm working on a small libarary that will parse and modify a certain type of configuration file. As suggested by wise people (I think) I'd like to hide away the implementation and offer the user a set of functions to use the library. I have questions mainly philosophical or concerning style. I'll put here my idea and it'd be very nice to get your opinions on it.
#ifndef CONFIGFILEAPI_H_INCLUDED
#define CONFIGFILEAPI_H_INCLUDED#include
#includenamespace cfgFileLib
{
//open and parse a file
// Returns:
// empty string "" if succesful
// error description if not
std::string openConfigFile (const std::string & fileName);//check if a symbol is defined
bool isDefined (const std::string & symbol);//how many values are assigned this symbol
int howMany (const std::string & symbol);//get first (or only) value assigned to the given symbol
bool getBool (const std::string & symbol);
int getInt (const std::string & symbol);
double getDouble (const std::string & symbol);
std::string getString (const std::string & symbol);//get all the values assgined to the given symbol
std::vector getAllBool (const std::string & symbol);
std::vector getAllInt (const std::string & symbol);
std::vector getAllDouble (const std::string & symbol);
std::vector getAllString (const std::string & symbol);
}
#endif- Does this design make sense in general? - Do I put it all whithin a namespace?
-
Hi, I'm working on a small libarary that will parse and modify a certain type of configuration file. As suggested by wise people (I think) I'd like to hide away the implementation and offer the user a set of functions to use the library. I have questions mainly philosophical or concerning style. I'll put here my idea and it'd be very nice to get your opinions on it.
#ifndef CONFIGFILEAPI_H_INCLUDED
#define CONFIGFILEAPI_H_INCLUDED#include
#includenamespace cfgFileLib
{
//open and parse a file
// Returns:
// empty string "" if succesful
// error description if not
std::string openConfigFile (const std::string & fileName);//check if a symbol is defined
bool isDefined (const std::string & symbol);//how many values are assigned this symbol
int howMany (const std::string & symbol);//get first (or only) value assigned to the given symbol
bool getBool (const std::string & symbol);
int getInt (const std::string & symbol);
double getDouble (const std::string & symbol);
std::string getString (const std::string & symbol);//get all the values assgined to the given symbol
std::vector getAllBool (const std::string & symbol);
std::vector getAllInt (const std::string & symbol);
std::vector getAllDouble (const std::string & symbol);
std::vector getAllString (const std::string & symbol);
}
#endif- Does this design make sense in general? - Do I put it all whithin a namespace?
Have a look at Boost.PropertyTree[^] I think it's a well designed library - it's worth taking a look at it's implementation. >> Does this design make sense in general? Normally you would create a class that is able to hold more than one configuration entry, and then something representing the various kinds of entries. >> Do I put it all whithin a namespace? That's usually a good idea :-) Best regards Espen Harlinn
Espen Harlinn Chief Architect - Powel AS Projects promoting programming in "natural language" are intrinsically doomed to fail. Edsger W.Dijkstra
-
Have a look at Boost.PropertyTree[^] I think it's a well designed library - it's worth taking a look at it's implementation. >> Does this design make sense in general? Normally you would create a class that is able to hold more than one configuration entry, and then something representing the various kinds of entries. >> Do I put it all whithin a namespace? That's usually a good idea :-) Best regards Espen Harlinn
Espen Harlinn Chief Architect - Powel AS Projects promoting programming in "natural language" are intrinsically doomed to fail. Edsger W.Dijkstra
-
Thanks Espen. I'll take a look at Boost.PropertyTree I didn't get what you meant by
Espen Harlinn wrote:
Normally you would create a class that is able to hold more than one configuration entry, and then something representing the various kinds of entries.
Something structured somewhat like this:
class ConfigEntry
{};
class ConfigNode : public ConfigEntry
{
typedef std::map > EntryMap;
EntryMap entryMap_;};
class ConfigValue : public ConfigEntry
{
};class StringConfigValue : public ConfigValue
{
std::string value_;
};class IntConfigValue : public ConfigValue
{
int value_;
};class ConfigFile : public ConfigNode
{
};This way the EntryMap can hold std::string, int and nested ConfigNode objects.
Espen Harlinn Chief Architect - Powel AS Projects promoting programming in "natural language" are intrinsically doomed to fail. Edsger W.Dijkstra
-
Hi, I'm working on a small libarary that will parse and modify a certain type of configuration file. As suggested by wise people (I think) I'd like to hide away the implementation and offer the user a set of functions to use the library. I have questions mainly philosophical or concerning style. I'll put here my idea and it'd be very nice to get your opinions on it.
#ifndef CONFIGFILEAPI_H_INCLUDED
#define CONFIGFILEAPI_H_INCLUDED#include
#includenamespace cfgFileLib
{
//open and parse a file
// Returns:
// empty string "" if succesful
// error description if not
std::string openConfigFile (const std::string & fileName);//check if a symbol is defined
bool isDefined (const std::string & symbol);//how many values are assigned this symbol
int howMany (const std::string & symbol);//get first (or only) value assigned to the given symbol
bool getBool (const std::string & symbol);
int getInt (const std::string & symbol);
double getDouble (const std::string & symbol);
std::string getString (const std::string & symbol);//get all the values assgined to the given symbol
std::vector getAllBool (const std::string & symbol);
std::vector getAllInt (const std::string & symbol);
std::vector getAllDouble (const std::string & symbol);
std::vector getAllString (const std::string & symbol);
}
#endif- Does this design make sense in general? - Do I put it all whithin a namespace?
If you're using this in C++ only, seems ok (let alone the preferences). However, I'd do this: - no namespace exports; be wary of linker decorations - export just the needed functions, not all (i.e. the "public" interface) - separate helpers from actors (i.e openConfigFile, isDefined vs getBool, getInt) - do not return std::string or others from functions; rather, return just simple testable values (int, bool) and change to bool openConfigFile(const std::string& filename, std::string& result); (or std::string* result) - if you'll get this used in other places, favor a C-like interface and do the plumbing code, such as BOOL WINAPI OpenConfigFileA(LPCSTR fileName, LPSTR* result); or use VARIANTs is needed in VBS. - or favor the COM-like exports with just structs with virtual pure functions and DllGetClassObject-like creators. There are many things to consider. I'm using sometimes even paper and pen to weight all these.