(j3.2006) 5.4.7p2 goes a little bit too far

Van Snyder Van.Snyder
Fri Jul 19 22:02:11 EDT 2013

5.4.7p2 says:

"If a nonpointer object has default initialization, it shall not appear
in a <data-stmt-object-list>."

I suspect we didn't intend to prohibit this program, which all of my
processors accept and produce what I expect:

  type :: T
    integer :: I = 3
    real :: R = 42.0
  end type

  type(t), parameter :: P = T()

  integer :: A(p%i), I

  data (a(i), i = 1, p%i) / 1, 2, 3 /
! This---------------^^^ is "in a <data-stmt-object-list>"

  print *, a


Perhaps 5.4.7p2 ought to be

"If a nonpointer variable has default initialization, it shall not
appear in a <data-stmt-object-list>."

F08/0062 established that it would be onerous to require a processor to
initialize part of an object using default initialization and part using
explicit initialization in a DATA statement.  I interpreted this to mean
"some components of...," not "some array elements of...," since that's
how Tobias posed the question.  A question Tobias didn't ask was whether
we intended to prohibit this:

  type(t) :: B(3)
  data B(2) / t(2,39.0) /

which doesn't impose the burden contemplated by F08/0062.

It is the same as (but less wordy than)

  type(t) :: B(3) = [ t(), t(2,39.0), t() ]

which is explicitly allowed by 5.2.3p1.

To remove this inconsistency, while preserving consistency with
F08/0062, it would be desirable if 5.4.7p2 were

"If a variable has default initialization, a subcomponent of that
variable shall not appear in a <data-stmt-object-list>."

(notice that "nonpointer" is no longer necessary) or

"If a type has default initialization, a subcomponent of a variable of
that type shall not appear in a <data-stmt-object-list>."

This is, after all, the reasoning behind the answer to F08/0062.  Some
minor work would also be needed in 5.2.3p1.

I believe the former could reasonably be addressed by an interpretation
("did we mean 'object' or 'variable?'").  The latter might be considered
to be a feature request, and therefore not an appropriate subject for an
interpretation, unless the question "did we mean 'object' or
'subcomponent of a variable?'" is not out of order.

Since we have decided to sit on our hands for seven years or so, there
is a good chance will not address such trivial irritations any time
soon, if ever.

5.7.4p2 caused a problem in a situation where I needed to initialize
most of an array to values specified by default initialization, and a
relatively smaller (but not small) subset to other values.  The
subscripts of the interesting elements are given by named constants,
which are generated by another processor.  It therefore makes for a very
fragile program if I look up the values of those constants in the output
of that processor and create an initialization of the form

  type(t) :: B(first:last) = [ t(), t(2,39.0), t(), ... ]

or a hairier mess involving named constants if the initialization is so
long that it won't fit in one statement.  If I change the input to the
program that generates the named constants, this kind of initialization
silently produces the wrong answer.

The program would be much less fragile if I could have written

  type(t) :: B(first:last)
  data B(an_interesting_one) / t(2,39.0) /
  data B ...

I can't remove the default initialization and do

  type(t) :: B(first:last) = t(3,42.0)
  data B(an_interesting_one) / t(2,39.0) /
  data B ...

because that falls afoul of 5.2.3p1.

I don't know apriori the numeric order of the interesting subscripts, so
the program is only marginally less fragile, and rather more expensive
to maintain, if I sort the named constants into numeric order, remove
default initialization and do

  type(t) :: B(first:last)
  integer, parameter :: n1 = first_interesting_one - first
  data ( b(i), i = first, first_interesting_one-1 ) / n1*t(3,42.0) /
  data b(first_interesting_one) / t(2,39.0) /
  integer, parameter :: n2 = second_interesting_one - first_interesting_one - 1
  data ( b(i), i = first_interesting_one+1, second_interesting_one-1 ) &
    & / n2*t(3,42.0) /

The somewhat dissatisfying solution I adopted was the following:

  type(t) :: B(first:last)
  logical, save :: FirstTime = .true.

  if ( firstTime ) then
    firstTime = .false.
    b(an_interesting_one) = t(2,39.)
    b(another_interesting_one) = ...
  end if

What was even more irritating, and expensive and embarrassing, was that
some of my processors were perfectly happy to accept what I had naively
hoped would work, i.e., perfectly happy to ignore 5.4.7p2 because it's
not a constraint.  I didn't get my ass bitten until one of my clients
complained that my code wouldn't compile.

More information about the J3 mailing list