• Data Initialisation

    From bart@21:1/5 to All on Mon Feb 26 16:29:22 2024
    One weak part of my C compiler is in initialisation:

    * No runtime data is allowed for {...} data inside functions

    * For nested structs and arrays, the pattern of {...} braces must
    exactly match the type structure, no missing braces allowed. (So {0}
    can't be used to zero a struct; only missing elements in arrays are allowed)

    * No support for designated initialisers

    * No support for compound literals (this is all part of the same aspect)

    So I thought I'd bite the bullet and fix all this. Until I came across
    section 6.7.9 (in my C99 draft standard, which is Initialisation).

    Paragraphs p17 to p38 described the rules for braces and for designated initialisers. I vaguely remember that it was complicated, I didn't
    realise it was this complicated!

    For example, p35 shows this example:

    struct { int a[3], b; } w[] = { [0].a = {1}, [1].a[0] = 2};

    I couldn't grok it. I had to use this loop to find out what was going on:

    for (int i=0; i<sizeof(w)/sizeof(w[0]); ++i) {
    printf("(%d %d %d) %d\n", w[i].a[0], w[i].a[1], w[i].a[2], w[i].b);
    }

    What this means is that you can declare a data strucure of any
    complexity, and initialise random, nested elements within a single set
    of { ... } braces. Here's a simple example:

    int A[][10] = {
    [7][3] = 99
    };

    I didn't know you could combine designators like this (I've never seen
    such examples), but I don't believe that is necessary. This example
    could also be written like this:

    int A[][10] = {
    [7] = {[3] = 99}
    };

    This doesn't require combining designators, and here there is a better
    match in the structure of the braces: '99' is inside 2 sets of braces
    rather than 1. But there is a hidden danger here too:

    int A[] = {
    [someexpr] = 99
    }

    For a local array, 'someexpr' could be 20, or it could be 2000000, high
    enough to cause stack overflow if you're lucky. Or it could just
    silently create a far bigger array than expected.

    Here's another example from p36:

    int a[MAX] = {1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0};

    p37 explains what it means, but not well. I think that the '6 4 2 0'
    values follow element a[MAX-5]. It also suggests that is it possible to
    define values multiple times:

    int A[] = {[3]=1, [3]=2, [3]=3};

    It can get even more hairy:

    int A[] = {[3]=1, [3]=2, [3]=A[3]};

    What is the value of A[3]? My guess was 2, but when I tried it, it was 0
    with gcc, 2 with tcc, an error with DMC, and -108754328 with clang.

    Presumably this is because it's using an uninitialised value of A[3]?
    But A[3] IS initialised, at least twice!


    This is all far more chaotic than I'd expected, and I decided not to
    bother upgrading my compiler. I have trouble implementing something that
    (1) I don't agree with because it's been poorly devised;(2) I don't
    understand anyway.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Keith Thompson on Mon Feb 26 19:26:02 2024
    On 26/02/2024 17:04, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    One weak part of my C compiler is in initialisation:

    * No runtime data is allowed for {...} data inside functions

    In other words, {...} initializers can only contain constant
    expressions. I presume this means you allow:
    int a = 42;
    int b = a;
    but not
    int a = 42;
    int b = {a};

    Actually, that one works. This won't work:

    int c[2] = {a, b};


    Out of curiousity, why are you using a C99 draft? Drafts of later
    editions are available.

    C99 is fine. There's little new in later versions that concerns my compiler.

    Paragraphs p17 to p38 described the rules for braces and for
    designated initialisers. I vaguely remember that it was complicated, I
    didn't realise it was this complicated!

    For example, p35 shows this example:

    struct { int a[3], b; } w[] = { [0].a = {1}, [1].a[0] = 2};

    That seems clear enough to me.

    Well not to me, even after I'd got over my surprise at seeing 3
    designators in a row.

    It initializes w[0].a to {1}, w[1].a[0]
    to 2, and everything else to the default value of 0.

    w[0].a = {1, 0, 0};
    w[1].a = {2, 0, 0};

    That is clearer. The only thing that elaborate initialiser adds, apart
    from confusion, is info about the maximum dimension of w.


    None of it is necessary. It's convenient.

    You don't get my point. Designators were added for their convenience,
    but that could have been done in a simple manner. It didn't need to
    complicate it by allowing arbitrarily long chains of designators:

    [3].a.b.c[4].d = x

    VLAs could also have been done in a far simpler manner (by making the
    VLA an attribute of a variable, not a type).

    That would have sufficed for nearly all (perhaps even all) of the uses
    I've ever seen of designated initialisers and VLAs.

    The convoluted examples are
    a result of not imposing arbitrary restrictions. I believe the examples
    in the standard are intended to clarify the rules and show what's
    possible, not as examples of good coding style.

    But it means implementators have to ensure those examples work.

    An example like this:

    int A[][10]= {
    [4][3]=10,
    [7][5]=20
    };

    works in gcc and tcc. But older compilers like DMC and lccwin have
    trouble with it (they work with single-designator examples).


    someexpr has to be a constant expression. You could as easily write:

    int A[someexpr+1];

    Designated initializers do not introduce any new danger.

    It means a rogue value could be somewhere in the hundred designators of
    A's init data rather than in one place.

    It can get even more hairy:

    int A[] = {[3]=1, [3]=2, [3]=A[3]};

    What is the value of A[3]? My guess was 2, but when I tried it, it was
    0 with gcc, 2 with tcc, an error with DMC, and -108754328 with clang.

    Presumably this is because it's using an uninitialised value of A[3]?
    But A[3] IS initialised, at least twice!

    "The evaluations of the initialization list expressions are
    indeterminately sequenced with respect to one another and thus the order
    in which any side effects occur is unspecified."

    gcc with extra warnings said nothing about it. But this:

    int A[2] = {A[0], A[1]};

    did produce a warning.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bart on Mon Feb 26 17:48:27 2024
    bart <bc@freeuk.com> writes:

    One weak part of my C compiler is in initialisation:

    [...]

    * No support for designated initialisers

    So I thought I'd bite the bullet and fix all this.

    Good show!

    Until I came across section 6.7.9 (in my C99 draft standard,
    which is Initialisation).

    Paragraphs p17 to p38 described the rules for braces and for
    designated initialisers. [...]

    What this means is that you can declare a data strucure of any
    complexity, and initialise random, nested elements within a
    single set of { ... } braces. Here's a simple example:

    int A[][10] = {
    [7][3] = 99
    };

    I didn't know you could combine designators like this (I've
    never seen such examples), but I don't believe that is
    necessary. This example could also be written like this:

    int A[][10] = {
    [7] = {[3] = 99}
    };

    It's true that the overall initializers in these two declarations
    have the same result. Note however that the individual
    initializer

    [7][3] = 99

    and the individual initializer

    [7] = {[3] = 99}

    have different meanings, and are different in at least two
    significant ways, depending on the context in which they appear.
    If you have difficulty seeing what those differences are, I'm
    sure Keith Thompson can explain what's going on. Depending on
    circumstances, either the first way or the second way could be
    a better choice; it depends on what one wants to accomplish
    and to convey.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Mon Feb 26 20:25:51 2024
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    bart <bc@freeuk.com> writes:

    One weak part of my C compiler is in initialisation:

    [...]

    * No support for designated initialisers

    So I thought I'd bite the bullet and fix all this.

    Good show!

    Until I came across section 6.7.9 (in my C99 draft standard,
    which is Initialisation).

    Paragraphs p17 to p38 described the rules for braces and for
    designated initialisers. [...]

    What this means is that you can declare a data strucure of any
    complexity, and initialise random, nested elements within a
    single set of { ... } braces. Here's a simple example:

    int A[][10] = {
    [7][3] = 99
    };

    I didn't know you could combine designators like this (I've
    never seen such examples), but I don't believe that is
    necessary. This example could also be written like this:

    int A[][10] = {
    [7] = {[3] = 99}
    };

    It's true that the overall initializers in these two declarations
    have the same result. Note however that the individual
    initializer

    [7][3] = 99

    and the individual initializer

    [7] = {[3] = 99}

    have different meanings, and are different in at least two
    significant ways, depending on the context in which they appear.
    If you have difficulty seeing what those differences are, I'm
    sure Keith Thompson can explain what's going on. Depending on
    circumstances, either the first way or the second way could be
    a better choice; it depends on what one wants to accomplish
    and to convey.

    Tim, you don't get to make an assertion and then pass off the work
    of explaining it to someone else.

    Do you agree that there are differences between the two
    initializers?

    Are you in fact able to explain what the differences
    are?

    If the answer to the preceding questions is Yes in
    both cases then it seems we have no disagreement.

    In any case you are under no obligation to provide
    an explanation (and I never said you were). Nor am I.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Tue Feb 27 12:42:32 2024
    On 26/02/2024 20:26, bart wrote:
    On 26/02/2024 17:04, Keith Thompson wrote:
    bart <bc@freeuk.com> writes:
    One weak part of my C compiler is in initialisation:

    * No runtime data is allowed for {...} data inside functions

    In other words, {...} initializers can only contain constant
    expressions.  I presume this means you allow:
         int a = 42;
         int b = a;
    but not
         int a = 42;
         int b = {a};

    Actually, that one works. This won't work:

        int c[2] = {a, b};

    I don't know if this is practical for you in your compiler, but one way
    to handle designated initialisers and non-constant initialisation would
    be to treat it as first doing a zero initialisation of the entire
    object, and then assignments. So given this:

    int a = 42;
    int b = a;
    int c[2] = { a, b };

    transform it into :

    int a;
    int b;
    int c[2];

    a = 42;
    b = a;

    memset(&c, 0, sizeof c);
    c[0] = a;
    c[1] = b;

    Obviously clearing the whole object "c" and then assigning the values to
    it is not the most efficient way to handle things if all the elements
    are initialised. But it can be effective if only a few elements are initialised explicitly, and it might be a relatively easy way to
    implement something that works well enough.




    Out of curiousity, why are you using a C99 draft?  Drafts of later
    editions are available.

    C99 is fine. There's little new in later versions that concerns my
    compiler.

    The big things in C11 are atomics and thread support, but those are
    optional. But there's also a few small things that are nice - anonymous structs and unions (supported by most compilers from long before C11,
    but standardised in C11) and _Static_assert() are very useful (for me,
    anyway). C17 is just a bug fix, but I think the typography improved so
    it's nicer to refer to C17 documents :-) All in all, I don't think it
    would be a large step to move from C99 to C17, if you skip the optional
    parts. (And VLAs and complex numbers are mandatory in C99, but optional
    in C11/C17.)

    C23 is another matter - it has a /lot/ of new features, and is the
    biggest change in C since C99.


    Paragraphs p17 to p38 described the rules for braces and for
    designated initialisers. I vaguely remember that it was complicated, I
    didn't realise it was this complicated!

    For example, p35 shows this example:

         struct { int a[3], b; } w[] = { [0].a = {1}, [1].a[0] = 2};

    That seems clear enough to me.

    Well not to me, even after I'd got over my surprise at seeing 3
    designators in a row.

     It initializes w[0].a to {1}, w[1].a[0]
    to 2, and everything else to the default value of 0.

        w[0].a = {1, 0, 0};
        w[1].a = {2, 0, 0};

    That is clearer. The only thing that elaborate initialiser adds, apart
    from confusion, is info about the maximum dimension of w.


    None of it is necessary.  It's convenient.

    You don't get my point. Designators were added for their convenience,
    but that could have been done in a simple manner. It didn't need to complicate it by allowing arbitrarily long chains of designators:

        [3].a.b.c[4].d = x

    Actually, it /does/. If you can't have arbitrarily long changes, you
    have arbitrary restrictions on the chains. It would be like saying you
    could write "int xs[2][3];" but not "int xs[2][3][5];", or that structs
    could only be nested 4 levels. It's unlikely that people will want to
    use deeply nested and long chains, but it's easier to say there are no
    limits than to give limits.

    (The C standard does give minimum "translation limits" for various
    things, but they are aimed to be so large that no real code will hit
    them, and few implementations have much in the way of arbitrary limits.)


    VLAs could also have been done in a far simpler manner (by making the
    VLA an attribute of a variable, not a type).

    That would have been a slightly different thing. (I'm not saying it
    would have been better or worse - I don't think it would make
    significant practical difference in real code.) In some languages,
    types are simpler and characteristics such as "const", "volatile", or
    the size of an array are attributes of the variable. In some, they are attributes of the type. That is the case for C. In C, if you write
    "int xs[10];", then you are declaring a variable "xs" of type "int
    [10]". The "[10]" is part of the type, not the variable. And thus the
    same applies if you declare "int ys[n];".

    I think a way to handle VLAs would be to treat :

    int xs[X];

    as :

    const size_t xs_size = X;
    int xs[xs_size];

    It is possible that this is not quite consistent with the standards if
    you have to evaluate "sizeof xs" and the expression "X" has
    side-effects, but it would surely work for any normal code.


    That would have sufficed for nearly all (perhaps even all) of the uses
    I've ever seen of designated initialisers and VLAs.

    The convoluted examples are
    a result of not imposing arbitrary restrictions.  I believe the examples
    in the standard are intended to clarify the rules and show what's
    possible, not as examples of good coding style.

    But it means implementators have to ensure those examples work.

    An example like this:

        int A[][10]= {
            [4][3]=10,
            [7][5]=20
        };

    works in gcc and tcc. But older compilers like DMC and lccwin have
    trouble with it (they work with single-designator examples).


    Emulate the ones that work :-)


    someexpr has to be a constant expression.  You could as easily write:

         int A[someexpr+1];

    Designated initializers do not introduce any new danger.

    It means a rogue value could be somewhere in the hundred designators of
    A's init data rather than in one place.

    In either case, you have a mistake in the source leading to faults in
    the generated code - I can't see a noticeable risk. And the alternative
    to designated initialisers would be to declare the array, then write the assignment "A[somexpr] = 99;" afterwards and have the bug there.

    At least with designated initialisers you can easily catch the bug if
    the array is declared with a specific size. And you can add a warning
    to your compiler for local arrays exceeding a certain size.


    It can get even more hairy:

         int A[] = {[3]=1, [3]=2, [3]=A[3]};

    What is the value of A[3]? My guess was 2, but when I tried it, it was
    0 with gcc, 2 with tcc, an error with DMC, and -108754328 with clang.

    Presumably this is because it's using an uninitialised value of A[3]?
    But A[3] IS initialised, at least twice!

    "The evaluations of the initialization list expressions are
    indeterminately sequenced with respect to one another and thus the order
    in which any side effects occur is unspecified."

    gcc with extra warnings said nothing about it. But this:

        int A[2] = {A[0], A[1]};

    did produce a warning.



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Thiago Adams on Tue Feb 27 13:37:00 2024
    On 27/02/2024 12:57, Thiago Adams wrote:
    On 26/02/2024 13:29, bart wrote:
    One weak part of my C compiler is in initialisation:

    * No runtime data is allowed for {...} data inside functions

    * For nested structs and arrays, the pattern of {...} braces must
    exactly match the type structure, no missing braces allowed. (So {0}
    can't be used to zero a struct; only missing elements in arrays are
    allowed)

    * No support for designated initialisers

    * No support for compound literals (this is all part of the same aspect)

    So I thought I'd bite the bullet and fix all this. Until I came across
    section 6.7.9 (in my C99 draft standard, which is Initialisation).

    Paragraphs p17 to p38 described the rules for braces and for
    designated initialisers. I vaguely remember that it was complicated, I
    didn't realise it was this complicated!

    For example, p35 shows this example:

         struct { int a[3], b; } w[] = { [0].a = {1}, [1].a[0] = 2};

    I couldn't grok it. I had to use this loop to find out what was going on:

       for (int i=0; i<sizeof(w)/sizeof(w[0]); ++i) {
           printf("(%d %d %d) %d\n", w[i].a[0], w[i].a[1], w[i].a[2],
    w[i].b);
       }

    What this means is that you can declare a data strucure of any
    complexity, and initialise random, nested elements within a single set
    of { ... } braces. Here's a simple example:

         int A[][10] = {
             [7][3] = 99
         };

    I didn't know you could combine designators like this (I've never seen
    such examples), but I don't believe that is necessary. This example
    could also be written like this:

         int A[][10] = {
             [7] = {[3] = 99}
         };

    This doesn't require combining designators, and here there is a better
    match in the structure of the braces: '99' is inside 2 sets of braces
    rather than 1. But there is a hidden danger here too:

         int A[] = {
            [someexpr] = 99
         }

    For a local array, 'someexpr' could be 20, or it could be 2000000,
    high enough to cause stack overflow if you're lucky. Or it could just
    silently create a far bigger array than expected.

    Here's another example from p36:

         int a[MAX] = {1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0};

    p37 explains what it means, but not well. I think that the '6 4 2 0'
    values follow element a[MAX-5]. It also suggests that is it possible
    to define values multiple times:

         int A[] = {[3]=1, [3]=2, [3]=3};

    It can get even more hairy:

         int A[] = {[3]=1, [3]=2, [3]=A[3]};

    What is the value of A[3]? My guess was 2, but when I tried it, it was
    0 with gcc, 2 with tcc, an error with DMC, and -108754328 with clang.

    Presumably this is because it's using an uninitialised value of A[3]?
    But A[3] IS initialised, at least twice!


    This is all far more chaotic than I'd expected, and I decided not to
    bother upgrading my compiler. I have trouble implementing something
    that (1) I don't agree with because it's been poorly devised;(2) I
    don't understand anyway.


    I also want to understand better this.
    I think the design must have some logic, I never stop to understand
    this. I think the best way is see some generated code, because it is
    maybe related with initialization performance. For instance, fill zeros
    first then do the other initialization.


    The order of initialisation is by the order of the initialisers
    (subject, as always, to the "as if" rule). So if you write :

    int A[] = {[3]=1, [3]=2, [3]=3};

    then the final "[3] = 3" is applied last, and overrides the others.
    This does not seem very useful to me, as it stands. However, like many features of C99, this has come about as a standardisation of gcc
    extensions, and that is how the gcc syntax worked - therefore, C99
    copied it for consistency with existing code. In gcc, it makes much
    more sense because you can write :

    int A[] = { [0 .. 9] = 1, [10 .. 29] = 2, [5] = 17 };

    and use this feature to override a value given in a range.

    <https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html>


    The order of evaluation of the initialisers, by contrast, is
    unspecified. It is also unspecified if overridden initialisers are
    evaluated (for their side-effects) at all. Again, this is consistent
    with the gcc extension, and it gives compilers more freedom in how they organise the code. That does mean that code like this:

    int A[] = {[3]=1, [3]=2, [3]=A[3]};

    does not have a well-defined and consistent result. But then, neither
    does "int x = x;", even though it is valid code. (It is sometimes used
    as an idiom to tell static error checkers and other programmers that you
    know "x" is not initialised, and that there should be no warning even if
    it appears to be read before initialisation.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Tue Feb 27 14:59:50 2024
    On Tue, 27 Feb 2024 13:37:00 +0100
    David Brown <david.brown@hesbynett.no> wrote:

    On 27/02/2024 12:57, Thiago Adams wrote:
    On 26/02/2024 13:29, bart wrote:
    One weak part of my C compiler is in initialisation:

    * No runtime data is allowed for {...} data inside functions

    * For nested structs and arrays, the pattern of {...} braces must
    exactly match the type structure, no missing braces allowed. (So
    {0} can't be used to zero a struct; only missing elements in
    arrays are allowed)

    * No support for designated initialisers

    * No support for compound literals (this is all part of the same
    aspect)

    So I thought I'd bite the bullet and fix all this. Until I came
    across section 6.7.9 (in my C99 draft standard, which is
    Initialisation).

    Paragraphs p17 to p38 described the rules for braces and for
    designated initialisers. I vaguely remember that it was
    complicated, I didn't realise it was this complicated!

    For example, p35 shows this example:

         struct { int a[3], b; } w[] = { [0].a = {1}, [1].a[0] = 2};

    I couldn't grok it. I had to use this loop to find out what was
    going on:

       for (int i=0; i<sizeof(w)/sizeof(w[0]); ++i) {
           printf("(%d %d %d) %d\n", w[i].a[0], w[i].a[1], w[i].a[2],
    w[i].b);
       }

    What this means is that you can declare a data strucure of any
    complexity, and initialise random, nested elements within a single
    set of { ... } braces. Here's a simple example:

         int A[][10] = {
             [7][3] = 99
         };

    I didn't know you could combine designators like this (I've never
    seen such examples), but I don't believe that is necessary. This
    example could also be written like this:

         int A[][10] = {
             [7] = {[3] = 99}
         };

    This doesn't require combining designators, and here there is a
    better match in the structure of the braces: '99' is inside 2 sets
    of braces rather than 1. But there is a hidden danger here too:

         int A[] = {
            [someexpr] = 99
         }

    For a local array, 'someexpr' could be 20, or it could be 2000000,
    high enough to cause stack overflow if you're lucky. Or it could
    just silently create a far bigger array than expected.

    Here's another example from p36:

         int a[MAX] = {1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0};

    p37 explains what it means, but not well. I think that the '6 4 2
    0' values follow element a[MAX-5]. It also suggests that is it
    possible to define values multiple times:

         int A[] = {[3]=1, [3]=2, [3]=3};

    It can get even more hairy:

         int A[] = {[3]=1, [3]=2, [3]=A[3]};

    What is the value of A[3]? My guess was 2, but when I tried it, it
    was 0 with gcc, 2 with tcc, an error with DMC, and -108754328 with
    clang.

    Presumably this is because it's using an uninitialised value of
    A[3]? But A[3] IS initialised, at least twice!


    This is all far more chaotic than I'd expected, and I decided not
    to bother upgrading my compiler. I have trouble implementing
    something that (1) I don't agree with because it's been poorly
    devised;(2) I don't understand anyway.


    I also want to understand better this.
    I think the design must have some logic, I never stop to understand
    this. I think the best way is see some generated code, because it
    is maybe related with initialization performance. For instance,
    fill zeros first then do the other initialization.


    The order of initialisation is by the order of the initialisers
    (subject, as always, to the "as if" rule). So if you write :

    int A[] = {[3]=1, [3]=2, [3]=3};

    then the final "[3] = 3" is applied last, and overrides the others.
    This does not seem very useful to me, as it stands. However, like
    many features of C99, this has come about as a standardisation of gcc extensions, and that is how the gcc syntax worked - therefore, C99
    copied it for consistency with existing code. In gcc, it makes much
    more sense because you can write :

    int A[] = { [0 .. 9] = 1, [10 .. 29] = 2, [5] = 17 };

    and use this feature to override a value given in a range.

    <https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html>


    The order of evaluation of the initialisers, by contrast, is
    unspecified. It is also unspecified if overridden initialisers are evaluated (for their side-effects) at all. Again, this is consistent
    with the gcc extension, and it gives compilers more freedom in how
    they organise the code. That does mean that code like this:

    int A[] = {[3]=1, [3]=2, [3]=A[3]};

    does not have a well-defined and consistent result. But then,
    neither does "int x = x;", even though it is valid code. (It is
    sometimes used as an idiom to tell static error checkers and other programmers that you know "x" is not initialised, and that there
    should be no warning even if it appears to be read before
    initialisation.)




    Designated initialization of auto objects is small and unimportant
    convenience feature.
    The big convenience gain comes when designated initializers applied
    to static and global objects. And in that case most of the problems
    mentioned above simply do not exist.

    If I were in bart's place, authoring compiler that does not try to be
    fully standard, I'd omit designated initialization of auto objects
    altogether.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Michael S on Tue Feb 27 15:35:50 2024
    On 27/02/2024 13:59, Michael S wrote:

    Designated initialization of auto objects is small and unimportant convenience feature.
    The big convenience gain comes when designated initializers applied
    to static and global objects. And in that case most of the problems
    mentioned above simply do not exist.

    If I were in bart's place, authoring compiler that does not try to be
    fully standard, I'd omit designated initialization of auto objects altogether.


    I would agree that that is a reasonable half-way step. It might be
    easier for him, but only Bart can answer that. It would certainly mean
    that some of the things he sees as complications no longer apply - all initialisers must be constants, so there are no questions about
    evaluation order. But he would still have to deal with overrides in initialiser lists, and what he described as "long chains of designators".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to bart on Tue Feb 27 21:59:02 2024
    On 26/02/2024 16:29, bart wrote:
    One weak part of my C compiler is in initialisation:
    ...
    This is all far more chaotic than I'd expected, and I decided not to
    bother upgrading my compiler. I have trouble implementing something that
    (1) I don't agree with because it's been poorly devised;(2) I don't understand anyway.

    I'm going to look at rewriting the front end of the compiler. This will
    add an extra pass, separating parsing + name resolution from type analysis.

    At the moment all that is done as one pass which gives little
    flexibility. I should be able to at least parse that data-init code and
    worry about what it means later. However member names can't be resolved
    until the second pass as they depend on what type things are.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)