A few thought regarding Cray's "Variable Length Array Proposal" <9302030459.AA09422awillow29.cray.com>

uunet!netcom.com!segfault!rfg uunet!netcom.com!segfault!rfg
Wed Feb 3 01:43:09 PST 1993


  
I read Cray's VLA proposal, and, in general, I think it is going in the
right direction.  I would like to pick a few nits however, and perhaps
suggest that a bit more crafting and wordsmithing is in order (here and
there).

>      Only  identifiers  with  automatic  storage duration can
>      have a type that  contains  a  VLA  type.

The proposal explicitly defines the term "an identifier with automatic
storage duration".  But that definition given DOES NOT include typedef
names.  Yet later on in the proposal it is noted quite clearly that
typedef names may indeed be defined in terms of VLA types.

I think the proposal ought not to try to talk about VLA *objects* on the
one hand and then about VLA typedefs on the other.  Rather, it should
just say that VLA *type specifications* can only appear in block scope
(or in prototype scope) and then say that objects explicitly declared
as either `static' or `extern' may not have types which are "VLA types".

I think this would simplify the presentation, and also help to clarify a
number of subtle points.

For example, using Tom's terminology, what does it mean for a type to
"contain" another type?  I have only a vague idea based upon my own best
guess.  From that guess, I'd have to conclude that (under this proposal):

		void foobar (int n)
		{
			static int (*ap) [n];
		}

... would be illegal.  But I can see no practical reason why it should be!
(Note that in this example, the type of `ap' *involves* a VLA type, but it
is not itself a VLA type.)

>      Furthermore, structure  and  union members cannot have VLA types.
>      Is this an acceptable limitation?
  
Yes.

>     -  For function prototypes, this proposal allows an iden-
>      tifier that is declared as a parameter and appears in an
>      array size expression to have its scope extended to  the
>      beginning of the parameter-type-list (rather than begin-
>      ning just after the completion of its  declarator)...

>      ...Is  this  fundamental change  to  C's  lexical  ordering
>      within  a  prototype acceptable?

No way!  It creates a horrendous amount of problems (some of which are
described in the proposal itself) and does so for little (if any) *real*
additional functionality.  TAKE THIS OUT!
 
>  6.1.2.4 (3.1.2.4) Storage Duration of Objects

>  ... If the object is variably qualified...
                        ^^^^^^^^^^^^^^^^^^
PLEASE PLEASE use a different term (e.g. "variable sized").  The term
"qualified" already has an established (and very different) meaning
with respect to ANSI/ISO C programs.

>  ... and the block is
>  entered by a jump to a labeled statement, then the  behavior
>  is  undefined.
       ^^^^^^^^^

Humm... Later on you say that jumping into a block past a declarative
statement which requires the elaboration of a variable-length array type
specification is simply illegal, and that a compile-time diagnostic is
required!  So which is it?  Compile-time diagnostic or undefined behavior
at run-time?

>  6.3.3.4 (3.3.3.4) The sizeof operator
>  
>  Semantics
>  
>       When applied to an operand that  has  array  type,  the
                                         ^^^

Don't forget about the operands which *are* array types, e.g.:

		typedef int array_type[n];

			... sizeof (array_type) ...

>  Rationale:
>  
>       The notion of ``size'' is an  important  part  of  such
>  operations  as  pointer increment, subscripting, and pointer
>  difference.  Although the sizeof operator will now produce a
>  value  computed at runtime, there still exists a consistency
>  when applied to the previously mentioned operations.

This needs some fleshing out.  I know what this is *trying* to say, but
the effects of VLA types on pointer arithmetic really need to be described
in more detail.  An example of pointer arithmetic on a pointer to a VLA
type would be helpful.

>  6.5.2 (3.5.2) Type Specifiers
>  
>  Contraint
>  
>       Only identifiers with block scope can have  a  variably
>  qualified  type.

What about prototype scope?

>  ISSUES
>  
>  Overview:
>  
>       This section discusses two  issues  about  declarations
>  containing  variable  length  array specifiers (i.e., VLAs).
>  First, VLAs must be declared at either block scope or  func-
>  tion  prototype scope, and must have automatic storage dura-
>  tion (i.e., no static storage duration objects).

Again, I think it is inappropariate to even discuss VLA *objects* at
such length.  Just say that VLA *types* can only appear in block scope
or prototype scope and that captures the major thrust.  Doing that should
also avoid any doubts about whether of not a type like `int (*)[n]' could
possibly be a function return type.  (It can't.)

>  ...then it must be an ordinary identifier.

What is an "ordinary identifier"?

>  6.5.4.2 (3.5.4.2) Array declarators
>  
>  Constraints
>  
>       The [ and ] shall delimit an expression or *.

The rationale for this `[*]' notation is not privided (as far as I could
see).  Why is it needed?  What does it do for us?  Can you get rid of it
if you get rid of the weird exception to the normal lexical scoping rules
for formal parameter names?

>  ...  In a parameter-type-
>  list, if an identifier is both declared as a  parameter  and
>  appears in  an array size expression that is not a constant
>  expression, then the scope of that identifier is extended to
>  the beginning of the parameter-type-list (rather than begin-
>  ning just after the completion of its declarator).

You have no idea what trouble this will cause!

>  Overview:
>  
>       By far the most controversial issue involves the ``lex-
>  ical  ordering  problem''  that is presented when prototypes
>  with variably qualified parameters are  used  and  the  size
>  expression  involves  an  identifier  that  is  not visible.

As well it should be!

>  Currently, programmers do not  need  to  concern  themselves
>  with the order in which formal parameters are specified, and
>  one common programming style is to declare the  most  impor-
>  tant  parameters  first.   Consider  the following prototype
>  definition:
>  
>  Example 14
>  
>    /* prototype declaration for old-style definition */
>  
>    void f(double a[*][*], int n);
>  
>    void f(a, n)
>       int n;
>       double a[n][n];
>    {
>       /* ... */
>    }
>  
>  The order in which the names are specified in the  parameter
>  list  does not depend on the order of the parameter declara-
>  tions themselves.  The accompanying prototype declaration is
>  compatible  with this definition and thus it seems appropri-
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  ate to allow the following prototype definition in  lieu  of
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  the previous old-style definition.
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Why not just disallow both??  You could have a rule which said that in
the case of an old-style (non-prototyped) declaration a given name of a
given formal parameter could *never* be used in any way in the specifica-
tion of the type of any other formal parameter whose name appeared earlier
than the given parameter name in the (old-style) parameter name list.

>  6.5.6 (3.5.6) Type definitions
>  
>  Constraints
>  
>       Typedef declarations which specify a variably qualified
>  type  shall  have  block scope.  The array size specified by
>  the variable length array type shall  be  evaluated
>  at the time the type definition is declared... 
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

When is a type definition "declared"?  (Next week perhaps? :-)

This really needs some serious wordsmithing.  The ANSI/ISO C standard
somehow managed to totally avoid introducing the concept of the dynamic
"elaboration" of declarative statements, although how this was done is
still a bit of an enigma (to me at least).

In contrast, if you look at the Ada standard (Oh God!  He said the `A' word!)
you will see that the authors of that document had the foresight and clarity
to understand that when dynamic types are involved, you simply cannot avoid
talking about the "dynamic elaboration" of declarative statements.  Of
course, when I say "talk about it" I really mean "define it".  You have
to define *when* things get elaborated, and what effect such elaborations
have.

I don't think there is any way to sweep this problem under the carpet
anymore for C... not if we are going to have VLA types!  Somebody will
*have* to define the "elaboration" of declarative statements AS A DYNAMIC
PROCESS which occurs at certain specified points in time.

>  6.7.1 (3.7.1) Function Definitions
>  
>  On entry to the function all size  expressions  of  variably
>  qualified parameters are evaluated.

How about saying instead "On entry to a given scope, all declarative
statements of the scope are elaborated in turn, in the sequence in
which they appear."?

>  7.6.2.1 (4.6.2.1) The longjmp function
>  
>  Description
>  
>       If a longjmp function invocation causes the termination
>  of  a  function  or  block  in  which  variable length array
>  objects are still allocated, then the behavior is undefined.
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

No good.  The behaviour *must* be defined.  Otherwise you have invented
a highly crippled VLA feature.

---------------------------------------------------------------------------

That's all the comments I have.  (I'll probably think of more later on.)

I know that I maybe sound like I'm really critical of the proposal, but I'm
not.  As I said at the top, I think it is headed in the right direction.


// Ronald F. Guilmette
//    domain address:	rfgasegfault.uucp
//    uucp address:	...!uunet!netcom.com!segfault!rfg



More information about the Numeric-interest mailing list