Proposed Improvements to the Presentation of Requirements for Functions

Document number:      WG21/N2121 = J16/06-0191

Date:                          2006-10-17

Revises:                     Library Active Issue 529

Project:                      Programming Language C++

Reference:                  N2009 = 06-0079

Reply to:                     Alan Talbot
cpp@alantalbot.com
Tele Atlas North America
11 Lafayette St
Lebanon NH 03766
USA

Introduction

After considerable discussion at the April 2006 Berlin meeting, there was some disagreement on the appropriate resolution of Issue 529–The standard encourages redundant and confusing preconditions (David Abrahams, 25 Oct 2005). This paper contains a survey of the actual instances and suggests resolutions for the problem identified in 529 and several other minor editorial issues.

The version of the Standard used was N2009=06-0079, dated 2006-04-21. I identified the instances of the problem by doing a text search on “Requires:”. I then examined each of the 164 instances for consistency and redundancy with the “Throws:” clause (if present). I also surveyed the cases where “Requires” was spelled “Precondition(s)”.

Discussion

Issue 529 points out the following possible inconsistency in the Standard. 17.3.1.3 [lib.structure.specifications] states:

Requires: the preconditions for calling the function

17.4.3.8 [lib.res.on.required] further states:

Violation of the preconditions specified in a function’s Required behavior: paragraph results in undefined behavior unless the function’s Throws: paragraph specifies throwing an exception when the precondition is violated.

The argument is made in 529 that this is contradictory because the definition of “precondition” is that it must be satisfied or undefined behavior will result. Since throwing is defined behavior, this creates a contradiction. 529 suggests removing the “unless” clause from this paragraph. At the Berlin meeting an argument was made against this that I find compelling: namely that doing so places the burden on the Requires paragraph to carefully exclude any behavior for which the function throws. Under some future circumstances, this could become quite complicated to write and to read. I find nothing unclear about the existing wording, although I do suggest a small grammatical improvement.

There is also a confusing (and embarrassing) typo in this paragraph, namely that it refers to the “Required behavior:” paragraph, not the “Requires:” paragraph.

529 goes on to suggest removing redundant Requires paragraphs in cases where the Requires paragraph does not specify any conditions that are not responded to by the Throws paragraph. There was wide consensus in Berlin was that this was a good idea. I have located the places where this occurs.

Global Changes

Order of paragraphs

The order of paragraphs in the function specification sections varies from function to function. This could lead to misreading. I suggest this be corrected by making all such sections follow the order in section 17.3.1.3 [lib.structure.specifications]. I have listed those sections that differ from that order. (An alternative would be to swap the position of “Effects” and “Preconditions” in the list and then edit those places that differ from that order. This might make for fewer changes.)

I have proposed these changes below by stating “Reorder” in the Proposed Changes section, rather than by detailed change language.

Name of the “Requires” paragraph

The term “Requires” is potentially confusing (with the “Required behavior” paragraph—note the typo in the current Standard), and is asymmetrical with the “Postconditions” paragraph. I suggest that the term “Preconditions” solves these problems. (Note this is already used in some places! See: 22.2.1.4.2 [lib.locale.codecvt.virtuals].)

I propose a global change in which all instances of “Requires” as it pertains to function preconditions, and all instances of “Precondition”, be changed to “Preconditions”.

Specific Changes

17.3.1.3 Specifications [lib.structure.specifications]

3              Descriptions of function semantics contain the following elements (as appropriate):155)

Requires: Preconditions: the preconditions for calling the function

Effects: the actions performed by the function

Postconditions: the observable results established by the function

Returns: a description of the value(s) returned by the function

Throws: any exceptions thrown by the function, and the conditions that would cause the exception

Complexity: the time and/or space complexity of the function

155) To save space, items that do not apply to a function are omitted. For example, if a function does not specify any further preconditions, there will be no “Requires” “Preconditions” paragraph.

Other possible issues:

This list does not include mention of the Replaceable: paragraph. Should it?

This list does not include mention of the Return type: paragraph. Should it?

17.4.3.8 Required paragraph [lib.res.on.required]

17.4.3.8 Required Preconditions paragraph                                    [lib.res.on.requiredpreconditions]

1          Violation of the preconditions specified in a function’s Required behavior: Preconditions: paragraph results in undefined behavior unless the function’s Throws: paragraph specifies throwing an exception when one or more of the preconditions is are violated.

18.5.1.1 Single-object forms [lib.new.delete.single]

18.5.1.2 Array forms [lib.new.delete.array]

18.7.2.3 set_unexpected [lib.set.unexpected]

18.7.3.2 set_terminate [lib.set.terminate]

20.3.1.5 Relational operators [lib.tuple.rel]

20.6.3 Temporary buffers [lib.temporary.buffer]

Reorder.

21.3.1 basic_string constructors [lib.string.cons]

3              Requires: pos <= str .size()

Reorder.

21.3.3 basic_string capacity [lib.string.capacity]

5              Requires: n <= max_size()

Reorder.

21.3.4 basic_string element access [lib.string.access]

2              Requires: pos < size()

21.3.5.2 basic_string::append [lib.string::append]

2              Requires: pos <= str .size()

Reorder.

21.3.5.3 basic_string::assign [lib.string::assign]

2              Requires: pos <= str .size()

Reorder.

21.3.5.4 basic_string::insert [lib.string::insert]

2              Requires: pos1 <= size() and pos2 <= str .size()

Reorder.

21.3.5.5 basic_string::erase [lib.string::erase]

1              Requires: pos <= size()

Reorder.

21.3.5.6 basic_string::replace [lib.string::replace]

2              Requires: pos1 <= size() && pos2 <= str .size().

Reorder.

21.3.5.7 basic_string::copy [lib.string::copy]

1              Requires: pos <= size()

Reorder.

21.3.5.8 basic_string::swap [lib.string::swap]

21.3.6 basic_string string operations [lib.string.ops]

Reorder.

21.3.6.7 basic_string::substr [lib.string::substr]

1              Requires: pos <= size()

Reorder.

23.2.3.4 list operations [lib.list.ops]

Reorder.

23.3.5.1 bitset constructors [lib.bitset.cons]

3              Requires: pos <= str .size().

Reorder.

23.3.5.2 bitset members [lib.bitset.members]

13            Requires: pos is valid

19            Requires: pos is valid

27            Requires: pos is valid

42            Requires: pos is valid

Reorder.

24.3.4 Iterator operations [lib.iterator.operations]

25.2.1 Copy [lib.alg.copy]

25.2.2 Swap [lib.alg.swap]

25.2.3 Transform [lib.alg.transform]

25.2.6 Generate [lib.alg.generate]

25.2.8 Unique [lib.alg.unique]

25.2.9 Reverse [lib.alg.reverse]

25.2.10 Rotate [lib.alg.rotate]

25.2.11 Random shuffle [lib.alg.random.shuffle]

25.2.12 Partitions [lib.alg.partitions]

25.3.1.1 sort [lib.sort]

25.3.1.2 stable_sort [lib.stable.sort]

25.3.1.3 partial_sort [lib.partial.sort]

25.3.1.4 partial_sort_copy [lib.partial.sort.copy]

25.3.4 Merge [lib.alg.merge]

25.3.5.2 set_union [lib.set.union]

25.3.5.3 set_intersection [lib.set.intersection]

25.3.5.4 set_difference [lib.set.difference]

25.3.5.5 set_symmetric_difference [lib.set.symmetric.difference]

25.3.6.1 push_heap [lib.push.heap]

25.3.6.2 pop_heap [lib.pop.heap]

25.3.6.4 sort_heap [lib.sort.heap]

25.3.9 Permutation generators [lib.alg.permutation.generators]

26.3.6 complex non-member operations [lib.complex.ops]

26.6.1 Accumulate [lib.accumulate]

26.6.2 Inner product [lib.inner.product]

26.6.3 Partial sum [lib.partial.sum]

26.6.4 Adjacent difference [lib.adjacent.difference]

27.4.2.6 ios_base callbacks [lib.ios.base.callback]

27.5.2.4.3 Get area [lib.streambuf.virt.get]

27.5.2.4.5 Put area [lib.streambuf.virt.put]

28.8.2 basic_regex constructors [lib.re.regex.construct]

Reorder.