Skip to content

[TASK] Review types used for size and indexing throughout codebase #4105

Open
@wphicks

Description

@wphicks

As noted in discussion on #4075, there are currently places in the codebase where we are using signed integers for positive indexing or to represent container sizes or other quantities that are better represented by other types (generally std::size_t). In order to clearly signal the semantic meaning of these variables, avoid signed/unsigned casting and comparisons, and to reduce the likelihood of overflow/underflow bugs, I propose the following rules:

  1. Avoid raw indexed loops wherever possible, instead giving preference to the relevant STL algorithm
  2. Always represent the size of an STL container with some_container<T>::size_type and use the same type for raw positive indexing. Liberal use of auto should make this less onerous, and rule 1 should make it rare.
  3. When representing the size of a quantity other than the size of a container or doing any other kind of raw positive indexing, use std::size_t unless there is a clear performance/resource reason to use a smaller type. In this case, an unsigned integer of the desired size should be used explicitly (e.g. uint32_t) and a comment should be added where the variable is declared explaining the performance consideration. If this is necessary for a custom container, alias custom_container<T>::size_type to the selected integer type.
  4. For negative indexing, the same basic rules apply. Use iterator::difference_type where possible or explicitly invoke std::ptrdiff_t otherwise.
  5. Use int to represent mathematical integers, quantities which can take on negative values and which are not sizes or indexes. A signed integer should not be used simply to include -1 as a special case; prefer std::optional or other ways of signaling this more clearly.

If we are better about rule 1, rules 2-5 should become less and less relevant.

TL;DR version:

  • for-loops bad, algorithms good
  • container::size_type for sizes and positive indexing where possible, std::size_t otherwise
  • iterator::difference_type for negative indexing where possible, std::ptrdiff_t otherwise
  • int is a mathematical quantity, not a size or an index
  • Performance exceptions are always allowed, but be explicit about them

I'm not married to these rules, but they seem like a reasonably small and complete set that is consistent with other style and usage guidelines. We can use this issue for any necessary discussion until #4075 is merged, and then I'll be happy to work on implementing whatever we land on.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions