2124. Seed sequence over-specified

Section: 29.5.3.2 [rand.req.seedseq] Status: NAD Submitter: Alberto Ganesh Barbati Opened: 2012-01-16 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [rand.req.seedseq].

View all issues with NAD status.

Discussion:

The seed sequence requirements described in 29.5.3.2 [rand.req.seedseq] appear to be over-specified. All seed sequence types are required to have a result_type nested type, a specific set of constructors, function members size() and param(), which are never used by the library. In fact, the only library components that actively use seed sequences are the random engines and all the engines need is the generate() member function. In particular, library components never attempts to construct seed sequence objects. These extraneous requirements are clearly written to describe the library provided type seed_seq type; while it's good that seed_seq has all those constructors and members, it's not a compelling reason to require a user-provided seed sequence type to implement all of them.

Suppose I want to write my own seed sequence class, this should do fine (and actually works as expected with libc++):

class my_seed_seq
{
  /* internals */
public:
  my_seed_seq(/* my own parameters */);

  template <class It>
  void generate(It first, It last);
};

my_seed_seq s(/* params */);
std::default_random_engine e(s);

The only reason to have these extra members would be to provide some support for generic serializability/persistence of seed sequence objects. I believe that would be out of the scope of the random library, so I doubt we will ever need those requirements in the future.

I therefore propose to remove all requirements from 29.5.3.2 [rand.req.seedseq] except for the presence of the generate() function.

[2012, Kona]

Move to Tenatively NAD. (Tentative as issue was not in pre-meeting mailing)

The 'overspecification', as such, was a deliberate intent to provide guarantees consumers of the whole random number framework may rely upon, especially in generic code. While the standard engines may be built without relying on these guarantees, this specification is part of a commitment to a broader framework, and Walter indicated future proposals in preparation for parallel generation of random numbers that may depend more inimately on these existing requirements.

Alisdair noted that the result_type typedef was a call-back to how we used to specify adaptable functors before TR1 result_of and the addition of std::bind and is probably not something we should be actively promoting in future libraries. However, it is too late to remove this requirement from seed sequences unless we are doing further surgery, as recommended by this issue.

Walter notes that the result_type protocol has not been formally deprecated by the standard. Alisdair replies that was the intent of deprecating the bind_1st/ unary_function set of templates in C++11, although we did not say anything about result_type in general.

Proposed resolution:

This wording is relative to the FDIS.

  1. Edit 29.5.3.2 [rand.req.seedseq] p2 as indicated:

    A class S satisfies the requirements of a seed sequence if the expressions shown in Table 115 are valid and have the indicated semantics, and if S also satisfies all other requirements of this section 29.5.3.2 [rand.req.seedseq]. In that Table and throughout this section:

    1. T is the type named by S's associated result_type;
    2. q is a value of S and r is a possibly const value of S; and
    3. ib and ie are input iterators with an unsigned integer value_type of at least 32 bits;
    4. rb and re are mutable random access iterators with an unsigned integer value_type of at least 32 bits;
    5. ob is an output iterator; and
    6. il is a value of initializer_list<T>.
  2. Ditto, in Table 115, remove all rows except the one describing q.generate(rb, re):

    Table 115 — Seed sequence requirements
    Expression Return type Pre/Post-condition Complexity
    S::result_type T T is an unsigned integer
    type (6.8.2 [basic.fundamental]) of at least 32 bits.
    compile-time
    S()   Creates a seed sequence with
    the same initial state as all
    other default-constructed seed
    sequences of type S.
    constant
    S(ib,ie)   Creates a seed sequence having
    internal state that depends on
    some or all of the bits of the
    supplied sequence [ib, ie).
    𝒪(ie - ib)
    S(il)   Same as S(il.begin(),
    il.end())
    .
    same as
    S(il.begin(),
    il.end())
    q.generate(rb,re) void Does nothing if rb == re.
    Otherwise, fills the supplied
    sequence [rb, re) with 32-bit
    quantities that depend on the
    sequence supplied to the
    constructor and possibly also
    depend on the history of
    generate's previous
    invocations.
    𝒪(re - rb)
    r.size() size_t The number of 32-bit units that
    would be copied by a call to
    r.param.
    constant
    r.param(ob) void Copies to the given destination a sequence of 32-bit units that
    can be provided to the
    constructor of a second object
    of type S, and that would
    reproduce in that second object
    a state indistinguishable from
    the state of the first object.
    𝒪(r.size())