tags:

views:

88

answers:

3

I'm writing a library and wonder what's the best practise for datatypes used in a public API.

Given the funtion

void foo (int bar)

which expects an index to some internal array/container. What type should that be? Because an index can never be negative I could use unsigned int or size_t. Or should I stick with a plain int and assert / throw if some invalid value is provided?

In general: Should I choose a type based on the valid data range (e.g. to avoid negative checks) or not?

EDIT: another example, suppose my library provides a function for printing a file. The user can choose the range of pages to be printed:

void print (int page_from, int page_to)
+1  A: 

The best advice here would probably be to go with the existing practice (i.e. what C++ standard libraries do). Broadly speaking, this means at least using an unsigned type here; if you're actually using that type directly as an array/pointer index (and your abstraction is transparent in that regard), then size_t might be called for.

If foo is a member function of some container-like class, then you may also consider typedefing something like size_type on it, and using that.

Pavel Minaev
A: 

I vote for using unsigned. Even better, use stdint.h and use something like uint32_t.

Drakosha
There is no `stdint.h` in C++ and even if there were, using a fixed-sized type is wrong. You can have an array with more than 2**32 elements. (Who said that 640kB of memory ought to be enough for anybody?)
avakar
<http://en.wikipedia.org/wiki/Stdint.h> I'm not suggesting using 32bit integers, u can also use uint64_t, i'm suggesting to *know* what is the size of your variable.
Drakosha
Thank you for the link. As I said, there is no `stdint.h` in C++. :) (It was added to C99, current C++ standard is based on C90. The next revision of the C++ standard will introduce `stdint.h`. At least one major C++ compiler doesn't support it yet -- msvc). Anyway, I don't think it's a good idea to fix the size of your variables, especially if they refer to indexes or sizes in memory (which has the tendency to grow beyond all limits). I thought we all learned this lesson during the 64-bit boom.
avakar
@Drakosha I would suggest that you shouldn't care about the _exact_ size of your variables, only that they are "big enough". That generally means using int or long, and letting the compiler pick the most effcient representation on the given hardware, maybe adding in some compile-time assertions that the types can hold the range of values that are required.
KeithB
+2  A: 

If the array/container you are talking about is just a generic abstract application-independent array, then the most appropriate type would be size_t. You can, of course, provide a typedef name for the type in your interface. Again, this is only appropriate when you are working with abstract arrays, like in a generic container library, or a generic sort function etc.

One you get into an application specific area, size_t is no longer the appropriate type. In your application specific area that index would normally have some application-specific semantics not immediately related to arrays. For example, it can be an "employee id" of some sort, or "cell number" or "color index" or something else. In such cases you would normally already have a pre-chosen integer type to represent the corresponding quantity. (And the choice will not normally have anything to do with arrays.) This is exactly the type you should use in your interface.

As for signedness/unsignedness of the type... I for one firmly believe that unsigned quantities should be represented by unsigned types, i.e. a normal array index should be unsigned.

AndreyT
+1: make a typedef for the quantity the number is supposed to represent.
avakar