Hi Martin,

The C design of VLAs misunderstood dependent typing.

For a program to  be validly typed when there are dependent types, you need to 
be able to write down the types of any values and variables at program points 
where they are in use.   This is problematic when there are assignments to 
variables involved in dependent types.  The values that the dependent types 
used are “gone”, so the program is no longer validly typed using the 
source-level types.  The Deputy system handled this by introducing temporary 
variables to hold values used in dependent types.  For C, that corresponds to 
introducing hidden state, which is not done anywhere else in the language.  It 
also doesn’t work when you have global variables involved in dependent types, 
as you potentially need an unlimited number of copies.

In your example:

> int len = 1;
> char buf[len]; // len is evaluated and the array has size 10
> len = 10; // has no impact on the type of 'buf'

What is the dependent type of buf after you’ve assigned to len?  The compiler 
can introduce a temporary, but the type is “gone” at the source level.   
Claiming that buf has the type of “array of length len” is not correct:

> int len = 1;
> char buf[len]; // len is evaluated and the array has size 10
> len = 10; // has no impact on the type of ‘buf’.   *** The dependent type of 
> buf in the source code (char [len]) is now wrong.***
   
There’s a misunderstanding of how type systems work.   There’s the static 
typing of a program - what is declared in the source code and “type checked” at 
compile time.  Then there is soundness: ensure that the program respects the 
types at runtime.  A proof of soundness takes the static type checking rules 
and combines them with the runtime semantics and shows that programs “never go 
wrong”, i.e. access values at the wrong type.  To have soundness, Deputy had to 
take the C source level programs and translate them to dependently-typed 
programs with extra state and extra runtime checks.  It’s a perfectly valid 
approach, but then one needs to understand that the source-level types no 
longer correspond to the dependent types used in type checking.   Deputy 
specifically restricted the dependent types of values stored on the heap: a 
value with a dependent type had to be stored in a member and the dependent type 
was specified in terms of other members in the same object.

As for the rules around scoping, we only need to rules that differ because the 
original design was flawed and missed common use cases.

David


> On Mar 13, 2025, at 11:16 PM, Martin Uecker <uec...@tugraz.at> wrote:
> 
> 
> Hi David,
> 
> Am Donnerstag, dem 13.03.2025 um 19:23 -0700 schrieb David Tarditi:
>> 
>> I skip your initiial part.  I think this was all discussed before
> 
> (also in WG14) and I still come to different conclusions.  Just
> two comments:
> 
> ...
>> 
>> The VLA semantics are also problematic. User can side-effect
>> variables used in a VLA declaration after the declaration, while
>> the declaration is in scope.  It is not obvious how to implement
>> bounds checking, because the bounds could be gone (invalid).
>>  It is a design flaw that the declared bounds can become invalid
>> while the declaration is in scope.
> 
> Variably modified types do not work like this C.  The size
> expression is evaluated at the point of declaration.  If there
> is a variable in it, it is never accessed later and changing it
> does not affect the type anymore.
> 
> int len = 1;
> char buf[len]; // len is evaluated and the array has size 10
> len = 10; // has no impact on the type of 'buf'
> 
> In fact, one can also have more complicated expressions.
> 
> int len = 11;
> char buf[len + 1]; // has size 11.
> 
> and those are also not re-evaluated later.
> 
> 
> This is exactly how it works in other dependently types languages,
> so I do not think one can make the case that C got these semantics 
> wrong.
> 
> Bounds checking also works already today: https://godbolt.org/z/5P8so1reb
> 
> (although there are still missing pieces which would be important
> but which compilers currently do not implement.  But for GCC I have
> a local branch which adds most of those.)
> 
> 
>> 
>> Finally, when you get to nested pointers, the syntax (and typing)
>> for VLAs becomes confusing. This isn’t VLAs fault. It is there in the
>> original C design.  
> 
> Your comments about C's syntax certainly have some truth to them,
> but I personally - as a C programmer and teacher - would find 
> it much worse to add new inconsistent rules to the language
> just to be able to write something in a more succinct way
> in some specific cases.  A programmer would still have to
> learn and nderstand the general C syntax and all the existing
> rules name lookup rules.
> 
> I do not think adding new inconsistent rules would make the
> language simpler and clearer in general, even it it may look
> like this when only considering a narrow use case.
> 
> 
> Martin
> 
> 

Reply via email to