• Bart's Language

    From bart@21:1/5 to Tim Rentsch on Mon Mar 17 23:51:59 2025
    On 06/03/2025 21:45, Tim Rentsch wrote:

    If you post some links where I can download a current user
    manual and a current compiler or interpreter, I will gladly
    withdraw my comment.


    Otherwise, I stand by my comment, and see no reason to
    consider your alleged environment as anything other than
    fiction-ware.


    The point of my question is not to determine if something exists but
    to find out what the purported language is. I'm tired of hearing
    bart brag about his personal programming language but never giving
    the specifics of what the language syntax and semantics are. It's
    like listening to a used car salesman who won't let you see the
    actual car.


    I'm not interested in the tools. What I am asking to see is
    the language.

    Bart:
    I'm working on a document that summaries the features.
    ...
    But, together with example programs, there should be enough info for someone, already familiar with C, to play with it, given a suitable implementation

    Or to understand some programs in it.

    This is the document I produced:

    https://github.com/sal55/langs/blob/master/MFeatures.md

    A couple of more substantial demo programs are here: https://github.com/sal55/langs/tree/master/MExamples

    (The bignum.m file was ported - by hand - to the bignum.c version that I
    posted recently.)

    I haven't provided an implementation, which would be a 400KB binary
    'mm.exe' that runs on Windows. I can do that if somebody wants and they
    can figure out how to get it past their AV.

    (There are other ways but they start to get complicated. A version for
    Linux, for an older language spec, that relies on a C backend, supplied
    as a C source file, is also a possibility, but that is getting beyond
    what I'm prepared to do. I've anyway done it all before.)

    I realise that this is not exactly on topic in a C forum, but a couple
    of people have been curious about this. I also didn't see any difference between a post in that thread, or a new one.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to bart on Tue Mar 18 12:17:14 2025
    bart <bc@freeuk.com> wrote:

    This is the document I produced:

    https://github.com/sal55/langs/blob/master/MFeatures.md

    A couple of more substantial demo programs are here: https://github.com/sal55/langs/tree/master/MExamples

    (The bignum.m file was ported - by hand - to the bignum.c version that I posted recently.)

    Looking at features, can you say if the program below works?
    And if it works, what is retrun value of foo? "Equvalent" can
    be written in C, but in C you have to keep sane order.

    proc baz =
    println "Line 4"
    end

    func c3(int x) int =
    println "Line 1"
    x
    end

    func foo() int =
    const a = b + c3(c)
    bar
    const b = c + c2(2)
    baz
    const c = c1(10)
    end

    func c2(int x) int =
    println "Line 3"
    x
    end

    proc bar =
    println "Line 2"
    end

    func c1(int x) int =
    println "Line 5"
    x

    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Waldek Hebisch on Tue Mar 18 13:54:55 2025
    On 18/03/2025 12:17, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    This is the document I produced:

    https://github.com/sal55/langs/blob/master/MFeatures.md

    A couple of more substantial demo programs are here:
    https://github.com/sal55/langs/tree/master/MExamples

    (The bignum.m file was ported - by hand - to the bignum.c version that I
    posted recently.)

    Looking at features, can you say if the program below works?
    And if it works, what is retrun value of foo? "Equvalent" can
    be written in C, but in C you have to keep sane order.


    There were some tweaks needed; it indicates some basic info missing from
    my write-up! (For example, that the function call needs to be bar() not
    bar; 'const' is only for compile-time expressions; and that C's 'const'
    doesn't exist - it only briefly mentions an attempt at 'let'.)

    The revised code is shown below, with what I assumed were your
    intentions. And below that is that code ported to C. Both versions
    produce this output:

    Line 1
    Line 2
    Line 3
    Line 4
    Line 5
    10
    Line 1
    Line 2
    Line 3
    Line 4
    Line 5
    10

    Note that both 'b' and 'c' in foo() are used uninitialised. I couldn't
    apply 'const' to those, as the const declaration would be separate from
    the assignment, and the later assignment is then not possible.

    (To answer your presumably implied point, in:

    print a
    int a:=100

    the assignment is done at that place in the code (after print), but the
    scope of 'a' is function-wide. My compiler doesn't detect accesses to unitialised variables, but I could add a debug option to clear
    stack-frame variables on function entry.)


    --------------------------
    proc baz =
    println "Line 4"
    end

    func c3(int x) int =
    println "Line 1"
    x
    end

    func foo() int =
    int a := b + c3(c)
    bar()
    int b := c + c2(2)
    baz()
    int c := c1(10)
    end

    func c2(int x) int =
    println "Line 3"
    x
    end

    proc bar =
    println "Line 2"
    end

    func c1(int x) int =
    println "Line 5"
    x
    end

    proc main =
    println foo()
    println foo()
    end

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

    #include <stdio.h>

    void baz();
    int c3(int);
    int c2(int);
    void bar();
    int c1(int);

    void baz() {
    puts("Line 4");
    }

    int c3(int x) {
    puts("Line 1");
    return x;
    }

    int foo() {
    int b, c;
    const int a = b+c3(c);
    bar();
    b = c + c2(2);
    baz();
    return (c = c1(10));
    }

    int c2(int x) {
    puts("Line 3");
    return x;
    }

    void bar() {
    puts("Line 2");
    }

    int c1(int x) {
    puts("Line 5");
    return x;
    }

    int main(void) {
    printf("%d\n", foo());
    printf("%d\n", foo());
    }

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to bart on Tue Mar 18 15:10:31 2025
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 12:17, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    This is the document I produced:

    https://github.com/sal55/langs/blob/master/MFeatures.md

    A couple of more substantial demo programs are here:
    https://github.com/sal55/langs/tree/master/MExamples

    (The bignum.m file was ported - by hand - to the bignum.c version that I >>> posted recently.)

    Looking at features, can you say if the program below works?
    And if it works, what is retrun value of foo? "Equvalent" can
    be written in C, but in C you have to keep sane order.


    There were some tweaks needed; it indicates some basic info missing from
    my write-up! (For example, that the function call needs to be bar() not
    bar; 'const' is only for compile-time expressions; and that C's 'const' doesn't exist - it only briefly mentions an attempt at 'let'.)

    The revised code is shown below, with what I assumed were your
    intentions.

    Well, my intentions beter correspond to the C version below:

    int foo() {
    const int c = c1(10);
    const int b = c + c2(2);
    const int a = b+c3(c);
    bar();
    baz();
    return c;
    }

    Part of the question was if "execution" of declarations is
    interleaved with execution of code or if declarations go
    before the code.

    I am not saying that you should implement this, rejecting the
    code as insane would be fine for me.

    And below that is that code ported to C. Both versions
    produce this output:

    Line 1
    Line 2
    Line 3
    Line 4
    Line 5
    10
    Line 1
    Line 2
    Line 3
    Line 4
    Line 5
    10

    Note that both 'b' and 'c' in foo() are used uninitialised. I couldn't
    apply 'const' to those, as the const declaration would be separate from
    the assignment, and the later assignment is then not possible.

    (To answer your presumably implied point, in:

    print a
    int a:=100

    the assignment is done at that place in the code (after print), but the
    scope of 'a' is function-wide. My compiler doesn't detect accesses to unitialised variables, but I could add a debug option to clear
    stack-frame variables on function entry.)

    I see. So your feature conflicts with C feature "variable which is
    initialized at declaration time is always used initialized".

    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Waldek Hebisch on Tue Mar 18 15:45:16 2025
    On 18/03/2025 15:10, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 12:17, Waldek Hebisch wrote:

    There were some tweaks needed; it indicates some basic info missing from
    my write-up! (For example, that the function call needs to be bar() not
    bar; 'const' is only for compile-time expressions; and that C's 'const'
    doesn't exist - it only briefly mentions an attempt at 'let'.)

    The revised code is shown below, with what I assumed were your
    intentions.

    Well, my intentions beter correspond to the C version below:

    int foo() {
    const int c = c1(10);
    const int b = c + c2(2);
    const int a = b+c3(c);
    bar();
    baz();
    return c;
    }

    Part of the question was if "execution" of declarations is
    interleaved with execution of code or if declarations go
    before the code.

    A declaration like:

    int a := x

    can be considered to be:

    int a; a := x

    where the declaration can go anywhere in the scope=, but the assignment
    must be done here. There are languages where you have:

    print x
    where x is ...

    But the typical usage pattern in my own programs is that local variable
    are declared before first use.

    (Maybe a compiler option can enforce that, but I don't see it as critical.)

    print a
    int a:=100

    the assignment is done at that place in the code (after print), but the
    scope of 'a' is function-wide. My compiler doesn't detect accesses to
    unitialised variables, but I could add a debug option to clear
    stack-frame variables on function entry.)

    I see. So your feature conflicts with C feature "variable which is initialized at declaration time is always used initialized".

    That doesn't happen here:

    int a = a;

    gcc (with no extra options) tcc and bcc both put some undefined value in a.

    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Tue Mar 18 17:31:39 2025
    On 18/03/2025 16:45, bart wrote:
    On 18/03/2025 15:10, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 12:17, Waldek Hebisch wrote:

    There were some tweaks needed; it indicates some basic info missing from >>> my write-up! (For example, that the function call needs to be bar() not
    bar; 'const' is only for compile-time expressions; and that C's 'const'
    doesn't exist - it only briefly mentions an attempt at 'let'.)

    The revised code is shown below, with what I assumed were your
    intentions.

    Well, my intentions beter correspond to the C version below:

    int foo() {
         const int c = c1(10);
         const int b = c + c2(2);
         const int a = b+c3(c);
         bar();
         baz();
         return c;
    }

    Part of the question was if "execution" of declarations is
    interleaved with execution of code or if declarations go
    before the code.

    A declaration like:

       int a := x

    can be considered to be:

       int a; a := x

    where the declaration can go anywhere in the scope=, but the assignment
    must be done here. There are languages where you have:

        print x
        where x is ...

    But the typical usage pattern in my own programs is that local variable
    are declared before first use.

    (Maybe a compiler option can enforce that, but I don't see it as critical.)

          print a
          int a:=100

    the assignment is done at that place in the code (after print), but the
    scope of 'a' is function-wide. My compiler doesn't detect accesses to
    unitialised variables, but I could add a debug option to clear
    stack-frame variables on function entry.)

    I see.  So your feature conflicts with C feature "variable which is
    initialized at declaration time is always used initialized".

    That doesn't happen here:

      int a = a;

    gcc (with no extra options) tcc and bcc both put some undefined value in a.

    It would be a little more accurate (in C terminology) to call it an "unspecified value" rather than an "undefined value" - gcc, and many
    other compilers, treat that as meaning "a" gets a valid int value, but
    you don't care which value it is. Using the value in "a" is allowed -
    i.e., it is not considered as undefined behaviour by the compiler. (I
    am not sure if the C standards require "int a = a;" to be treated like
    that - I suspect that it is undefined behaviour from the standards
    viewpoint, but defined by the implementation.)



    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a common
    idiom meaning "I know it is not clear to the compiler that the variable
    is always initialised before use, but /I/ know it is - so disable the use-without-initialisation warnings for this variable". So it makes
    perfect sense for the compiler not to warn about it!

    gcc does have a "-Winit-self" warning (not part of -Wall or -Wextra)
    that will warn on "int a = a;". (It is enabled by -Wall in C++,
    however, since in C++ such code can have very different semantics for
    more advanced types.)

    "int a = a + 1;", on the other hand, clearly attempts to read the value
    of "a" before it is initialised, and a warning is issued if
    "-Wuninitialized" is enabled. This warning is part of "-Wall".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kenny McCormack@21:1/5 to david.brown@hesbynett.no on Tue Mar 18 18:04:27 2025
    In article <vrc75b$2r4lt$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    ...
    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a common
    idiom meaning "I know it is not clear to the compiler that the variable
    is always initialised before use, but /I/ know it is - so disable the >use-without-initialisation warnings for this variable". So it makes
    perfect sense for the compiler not to warn about it!

    Wouldn't it just be easier and clearer to write: int a = 0;
    and be done with it?

    "int a = a + 1;", on the other hand, clearly attempts to read the value
    of "a" before it is initialised, and a warning is issued if
    "-Wuninitialized" is enabled. This warning is part of "-Wall".

    How is: int a = a + 1;
    conceptually different from: int a = a;

    Both are expressions involving 'a'.
    Isn't 'a' being used un-initialised in both cases?

    (You have to know the value of 'a' in order to evaluate the expression: a)

    --
    "If our country is going broke, let it be from feeding the poor and caring for the elderly. And not from pampering the rich and fighting wars for them."

    --Living Blue in a Red State--

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Kenny McCormack on Tue Mar 18 19:36:16 2025
    On 18.03.2025 19:04, Kenny McCormack wrote:
    In article <vrc75b$2r4lt$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    ...
    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a common
    idiom meaning "I know it is not clear to the compiler that the variable
    is always initialised before use, but /I/ know it is - so disable the
    use-without-initialisation warnings for this variable".

    Wow! - It would never have occurred to me that "int a = a;" being
    considered an idiom, let alone a "common idiom".

    I certainly never saw it in any C code nor have seen it mentioned
    as idiomatic code [to prevent compiler warning messages]. - This is
    IMO just sick; in all respects. Compilers not warning about it (you
    may have just missed to complete the RHS expression), programmers
    working around a compiler deficiency by code that just rises more
    questions (than solving any issue).

    So it makes perfect sense for the compiler not to warn about it!

    (Obviously mileages on that vary.)


    Wouldn't it just be easier and clearer to write: int a = 0;
    and be done with it?

    Indeed! - More generally, there's a [general, non-language specific]
    coding _idiom_ to ("always", sort of) initialize your variables, and
    this is certainly part of many coding guidelines and recommendations
    I've seen.


    "int a = a + 1;", on the other hand, clearly attempts to read the value
    of "a" before it is initialised, and a warning is issued if
    "-Wuninitialized" is enabled. This warning is part of "-Wall".

    How is: int a = a + 1;
    conceptually different from: int a = a;

    Both are expressions involving 'a'.
    Isn't 'a' being used un-initialised in both cases?

    (You have to know the value of 'a' in order to evaluate the expression: a)

    Yes. (Unless it's really an "idiom"; then we can justify every idea
    we like by that classification.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Janis Papanagnou on Tue Mar 18 19:11:21 2025
    On 2025-03-18, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    On 18.03.2025 19:04, Kenny McCormack wrote:
    In article <vrc75b$2r4lt$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    ...
    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a common
    idiom meaning "I know it is not clear to the compiler that the variable
    is always initialised before use, but /I/ know it is - so disable the
    use-without-initialisation warnings for this variable".

    Wow! - It would never have occurred to me that "int a = a;" being
    considered an idiom, let alone a "common idiom".

    Suppose the program is well-defined with "int a;"; just the compiler
    is not smart enough to analyze it, and so it warns about a potential
    use of an uninitialized variable.

    When you add this "idiom", you may be introducing undefined behavior
    into the declaration.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Kenny McCormack on Tue Mar 18 20:51:44 2025
    On 18/03/2025 19:04, Kenny McCormack wrote:
    In article <vrc75b$2r4lt$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    ...
    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a common
    idiom meaning "I know it is not clear to the compiler that the variable
    is always initialised before use, but /I/ know it is - so disable the
    use-without-initialisation warnings for this variable". So it makes
    perfect sense for the compiler not to warn about it!

    Wouldn't it just be easier and clearer to write: int a = 0;
    and be done with it?

    Write that if that's what you want.

    I don't think I have ever actually written "int a = a;" in my own code -
    but I know the idiom. In almost all cases, I don't declare a variable
    until I have something to put in it, so I have a real initialiser. And
    if I don't, I prefer to leave it uninitialised - then the compiler can
    tell me if I haven't initialised it when I use it. "int a = a;" would
    only be useful in fairly niche cases.


    "int a = a + 1;", on the other hand, clearly attempts to read the value
    of "a" before it is initialised, and a warning is issued if
    "-Wuninitialized" is enabled. This warning is part of "-Wall".

    How is: int a = a + 1;
    conceptually different from: int a = a;

    Both are expressions involving 'a'.
    Isn't 'a' being used un-initialised in both cases?


    The case "int a = a;" is recognised as an idiom by a number of compilers
    (such as gcc). A brief check suggests that gcc will generate code as it
    would for "int a = 0;", but it is certainly possible for a compiler to
    avoid any kind of initialisation here and let the register or stack slot
    used for "a" stay as it was. That would be a pretty minor efficiency improvement, but optimised code is mostly the sum of lots of tiny
    improvements.

    (You have to know the value of 'a' in order to evaluate the expression: a)


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Kenny McCormack on Tue Mar 18 19:37:37 2025
    gazelle@shell.xmission.com (Kenny McCormack) writes:
    In article <vrc75b$2r4lt$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    ...
    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a common
    idiom meaning "I know it is not clear to the compiler that the variable
    is always initialised before use, but /I/ know it is - so disable the >>use-without-initialisation warnings for this variable". So it makes >>perfect sense for the compiler not to warn about it!

    Wouldn't it just be easier and clearer to write: int a = 0;
    and be done with it?

    Would cost an additional instruction at least...

    I've never seen the construct 'int a = a;' ever used, myself.

    I'll pay the extra instruction for a deterministic value.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to David Brown on Tue Mar 18 23:27:21 2025
    On 18.03.2025 20:51, David Brown wrote:
    [...] A brief check suggests that gcc will generate code as it
    would for "int a = 0;", but it is certainly possible for a compiler to
    avoid any kind of initialisation here and let the register or stack slot
    used for "a" stay as it was. That would be a pretty minor efficiency improvement,

    but optimised code is mostly the sum of lots of tiny improvements.

    Interesting view. I've learned that such Peephole Optimizations were
    not what contribute to optimizations most. It's rather transformations
    of structure of various forms that is what "mostly" matters. - That's
    what I've learned many decades ago, of course. - So I'm curious where
    you've got that view from. (Some reference, maybe? Or was that just a
    personal opinion?)

    Janis, wondering

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Waldek Hebisch on Tue Mar 18 22:19:48 2025
    On 18/03/2025 15:10, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 12:17, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    This is the document I produced:

    https://github.com/sal55/langs/blob/master/MFeatures.md

    A couple of more substantial demo programs are here:
    https://github.com/sal55/langs/tree/master/MExamples

    (The bignum.m file was ported - by hand - to the bignum.c version that I >>>> posted recently.)

    Looking at features, can you say if the program below works?
    And if it works, what is retrun value of foo? "Equvalent" can
    be written in C, but in C you have to keep sane order.


    There were some tweaks needed; it indicates some basic info missing from
    my write-up! (For example, that the function call needs to be bar() not
    bar; 'const' is only for compile-time expressions; and that C's 'const'
    doesn't exist - it only briefly mentions an attempt at 'let'.)

    The revised code is shown below, with what I assumed were your
    intentions.

    Well, my intentions beter correspond to the C version below:

    int foo() {
    const int c = c1(10);
    const int b = c + c2(2);
    const int a = b+c3(c);
    bar();
    baz();
    return c;
    }


    In this case, just write it like that, and only adjust it for the
    somewhat different syntax:

    func foo:int =
    let int c := c1(10)
    let int b := c + c2(2)
    let int a := b+c3(c)
    bar()
    baz()
    return c
    end

    'let' seems to still work, and will do the job of C's const in simple
    cases like this.

    Versions in both languages now report Lines 5 3 1 2 4.

    The 'let' here is enforced more strongly that C's 'const', in that it
    /has/ to be initialised. C needs the right compiler and the right options
    to complain about it.











    Part of the question was if "execution" of declarations is
    interleaved with execution of code or if declarations go
    before the code.

    I am not saying that you should implement this, rejecting the
    code as insane would be fine for me.

    And below that is that code ported to C. Both versions
    produce this output:

    Line 1
    Line 2
    Line 3
    Line 4
    Line 5
    10
    Line 1
    Line 2
    Line 3
    Line 4
    Line 5
    10

    Note that both 'b' and 'c' in foo() are used uninitialised. I couldn't
    apply 'const' to those, as the const declaration would be separate from
    the assignment, and the later assignment is then not possible.

    (To answer your presumably implied point, in:

    print a
    int a:=100

    the assignment is done at that place in the code (after print), but the
    scope of 'a' is function-wide. My compiler doesn't detect accesses to
    unitialised variables, but I could add a debug option to clear
    stack-frame variables on function entry.)

    I see. So your feature conflicts with C feature "variable which is initialized at declaration time is always used initialized".


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Kenny McCormack on Tue Mar 18 23:52:20 2025
    gazelle@shell.xmission.com (Kenny McCormack) writes:

    In article <vrc75b$2r4lt$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    ...

    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a
    common idiom meaning "I know it is not clear to the compiler that
    the variable is always initialised before use, but /I/ know it is -
    so disable the use-without-initialisation warnings for this
    variable". So it makes perfect sense for the compiler not to warn
    about it!

    An addle-brained view. Anyone who thinks that should be forcibly
    removed from any activity involving software development.

    Wouldn't it just be easier and clearer to write: int a = 0;
    and be done with it?

    There are two problems: one, the semantics are different; and two,
    the impression given of the author's intent is different. It's kind
    of like saying "isn't it just easier and clearer to write 'red'
    rather than 'yellow'?" Writing 'int a = 0;' might be better or it
    might be worse, depending on one's point of view, but it shouldn't
    be considered either more clear or less clear, because it isn't
    saying the same thing.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Janis Papanagnou on Wed Mar 19 11:40:32 2025
    On 18/03/2025 23:27, Janis Papanagnou wrote:
    On 18.03.2025 20:51, David Brown wrote:
    [...] A brief check suggests that gcc will generate code as it
    would for "int a = 0;", but it is certainly possible for a compiler to
    avoid any kind of initialisation here and let the register or stack slot
    used for "a" stay as it was. That would be a pretty minor efficiency
    improvement,

    but optimised code is mostly the sum of lots of tiny improvements.

    Interesting view. I've learned that such Peephole Optimizations were
    not what contribute to optimizations most. It's rather transformations
    of structure of various forms that is what "mostly" matters. - That's
    what I've learned many decades ago, of course. - So I'm curious where
    you've got that view from. (Some reference, maybe? Or was that just a personal opinion?)


    Some optimisations have big effects, certainly - good register
    allocation and lifetime analysis, and optimisations that move code
    around (loop transformations, inlining, etc.) are the big factors.
    However, in modern compilers there are lots of minor optimisations that
    only apply in a few cases and only help a few percent in those cases.
    Each does little on its own, but in sum the results can be significant.

    But you are right that it is not really fair to say that optimisation is "mostly" the sum of tiny improvements - it's a small number of big and important transforms, and /then/ the sum of a large number of small ones.

    One complicating factor about these small optimisations is that the
    observable effect on code speed is highly dependent on the rest of the
    code and the type of processor involved. A peephole optimisation that
    removes an extra register-to-register move will save a cycle on a microcontroller, but on an x86 system such a move might be merged in the register renaming hardware of the cpu's prefetch queues and thus
    disappear entirely. Reducing instruction cycles matters a lot on microcontrollers, while on a big processor they might not make any
    difference if the cpu is waiting for memory.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Tim Rentsch on Wed Mar 19 11:43:40 2025
    On 19/03/2025 07:52, Tim Rentsch wrote:
    gazelle@shell.xmission.com (Kenny McCormack) writes:

    In article <vrc75b$2r4lt$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    ...

    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a
    common idiom meaning "I know it is not clear to the compiler that
    the variable is always initialised before use, but /I/ know it is -
    so disable the use-without-initialisation warnings for this
    variable". So it makes perfect sense for the compiler not to warn
    about it!

    An addle-brained view. Anyone who thinks that should be forcibly
    removed from any activity involving software development.


    I think this is the first time in years that you have quoted me, keeping
    the attribution in place, and replied to directly to the quoted part. Unsurprisingly, it looks like you put more effort into thinking up a
    "cool" insult than into reading what I actually wrote.

    I look forward to your next well-considered reply, perhaps some time in
    the autumn.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rosario19@21:1/5 to Tim Rentsch on Wed Mar 19 13:23:57 2025
    On Tue, 18 Mar 2025 23:52:20 -0700, Tim Rentsch wrote:

    (Kenny McCormack) writes:

    David Brown wrote:
    ...

    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a
    common idiom meaning "I know it is not clear to the compiler that
    the variable is always initialised before use, but /I/ know it is -
    so disable the use-without-initialisation warnings for this
    variable". So it makes perfect sense for the compiler not to warn
    about it!

    An addle-brained view. Anyone who thinks that should be forcibly
    removed from any activity involving software development.

    Wouldn't it just be easier and clearer to write: int a = 0;
    and be done with it?

    There are two problems: one, the semantics are different; and two,
    the impression given of the author's intent is different. It's kind
    of like saying "isn't it just easier and clearer to write 'red'
    rather than 'yellow'?" Writing 'int a = 0;' might be better or it
    might be worse, depending on one's point of view, but it shouldn't
    be considered either more clear or less clear, because it isn't
    saying the same thing.

    int a=a;
    for me initialize "a" variable with a value the compiler found right
    as in

    int a;

    only possibly silence compiler warning for variable not initializated

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Janis Papanagnou on Wed Mar 19 15:56:55 2025
    On 18/03/2025 19:36, Janis Papanagnou wrote:
    On 18.03.2025 19:04, Kenny McCormack wrote:
    In article <vrc75b$2r4lt$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    ...
    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a common
    idiom meaning "I know it is not clear to the compiler that the variable
    is always initialised before use, but /I/ know it is - so disable the
    use-without-initialisation warnings for this variable".

    Wow! - It would never have occurred to me that "int a = a;" being
    considered an idiom, let alone a "common idiom".


    It is certainly an idiom, and certainly viewed by gcc as a way to avoid
    an "uninitialized" warning (unless "-Winit-self" is also enabled), and
    it is an idiom I have seen documented in at least one other compiler
    (though I can't remember which - I've read many compiler manuals over
    the decades).

    But judging from the posts here, it may not be a "common" idiom.

    (And I am not suggesting it is a /good/ idiom. It's not one I use
    myself, and I have "-Winit-self" in my list of standard warning flags
    because it is conceivable that I write "int a = a;" in error. But there
    are lots of idioms and common practices in C that I don't like personally.)


    As far as I understand it (and I hope to be corrected if I am wrong),
    "int a = a;" is not undefined behaviour as long as the implementation
    does not have trap values for "int". It simply leaves "a" as an
    unspecified value - just like "int a;" does. Thus it is not in any way
    "worse" than "int a;" as far as C semantics are concerned. Any
    difference is a matter of implementation - and the usual implementation
    effect is to disable "not initialised" warnings.

    It is in much the same category as "(void) x;", which is an idiom for
    skipping an "unused variable" or "unused parameter" warning.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to David Brown on Wed Mar 19 16:38:30 2025
    David Brown <david.brown@hesbynett.no> writes:
    On 18/03/2025 19:36, Janis Papanagnou wrote:
    On 18.03.2025 19:04, Kenny McCormack wrote:
    In article <vrc75b$2r4lt$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    ...
    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a common
    idiom meaning "I know it is not clear to the compiler that the variable >>>> is always initialised before use, but /I/ know it is - so disable the
    use-without-initialisation warnings for this variable".

    Wow! - It would never have occurred to me that "int a = a;" being
    considered an idiom, let alone a "common idiom".


    It is certainly an idiom, and certainly viewed by gcc as a way to avoid
    an "uninitialized" warning (unless "-Winit-self" is also enabled), and
    it is an idiom I have seen documented in at least one other compiler
    (though I can't remember which - I've read many compiler manuals over
    the decades).

    But judging from the posts here, it may not be a "common" idiom.

    (And I am not suggesting it is a /good/ idiom. It's not one I use
    myself, and I have "-Winit-self" in my list of standard warning flags
    because it is conceivable that I write "int a = a;" in error. But there
    are lots of idioms and common practices in C that I don't like personally.)


    As far as I understand it (and I hope to be corrected if I am wrong),
    "int a = a;" is not undefined behaviour as long as the implementation
    does not have trap values for "int". It simply leaves "a" as an
    unspecified value - just like "int a;" does. Thus it is not in any way >"worse" than "int a;" as far as C semantics are concerned. Any
    difference is a matter of implementation - and the usual implementation >effect is to disable "not initialised" warnings.

    It is in much the same category as "(void) x;", which is an idiom for >skipping an "unused variable" or "unused parameter" warning.


    I would disagree with this last statement. (void)x is genuinely
    useful and has no ill side effects. 'int a = a;' is exactly
    the opposite - not useful and has potenial bad side effects.

    I've used the (void) construct when inline functions are defined
    in a header file, but not used by a source file that includes the
    header. (void) function will quiet the unused function warnings
    from the compiler without having to add #if to the header.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to David Brown on Wed Mar 19 17:07:23 2025
    On 2025-03-19, David Brown <david.brown@hesbynett.no> wrote:
    On 18/03/2025 19:36, Janis Papanagnou wrote:
    On 18.03.2025 19:04, Kenny McCormack wrote:
    In article <vrc75b$2r4lt$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    ...
    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a common
    idiom meaning "I know it is not clear to the compiler that the variable >>>> is always initialised before use, but /I/ know it is - so disable the
    use-without-initialisation warnings for this variable".

    Wow! - It would never have occurred to me that "int a = a;" being
    considered an idiom, let alone a "common idiom".


    It is certainly an idiom, and certainly viewed by gcc as a way to avoid
    an "uninitialized" warning (unless "-Winit-self" is also enabled), and
    it is an idiom I have seen documented in at least one other compiler
    (though I can't remember which - I've read many compiler manuals over
    the decades).

    I think that this "idiom" is a complete fluke, except in that compiler
    where it was documented.

    It's easy to see how it can arise "naturally" in a compiler which has
    warnings about both uses of uninitialized variables, and about
    variables being left uninitialized.

    In the "int a = a;" declaration, the initializing expression "a"
    is in the scope of a.

    Suppose the compiler, when processing the declaration, begins
    by extending the compile-time scope object with the name "a",
    and seeing that an initializer is present in the syntax, it
    flags "a" as being initialized. That suppresses any diagnostics
    about a not being initialized.

    Then it subsequently processes the initializing expression "a".
    At that point "a" is flagged initialized, and so no diagnostic
    occurs for the use of uninitialized "a".

    That's a bug in the compiler, not an idiom. "a" is positively *not*
    initialized until the initializing expression is evaluated.
    The compiler must *not* set this "initialized" flag in the
    scope information until it has compiled the initializing expression
    and moved on to the next declarator, declaration or statement.
    That way when it is code-walking the initializing expression,
    it will encounter "a" and correctly report that it's being
    accessed without having been initialized.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Scott Lurndal on Thu Mar 20 02:02:39 2025
    scott@slp53.sl.home (Scott Lurndal) writes:

    David Brown <david.brown@hesbynett.no> writes:

    On 18/03/2025 19:36, Janis Papanagnou wrote:

    On 18.03.2025 19:04, Kenny McCormack wrote:

    In article <vrc75b$2r4lt$1@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    ...

    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a
    common idiom meaning "I know it is not clear to the compiler
    that the variable is always initialised before use, but /I/ know
    it is - so disable the use-without-initialisation warnings for
    this variable".

    Wow! - It would never have occurred to me that "int a = a;" being
    considered an idiom, let alone a "common idiom".

    It is certainly an idiom, and certainly viewed by gcc as a way to
    avoid an "uninitialized" warning (unless "-Winit-self" is also
    enabled), and it is an idiom I have seen documented in at least one
    other compiler (though I can't remember which - I've read many
    compiler manuals over the decades).

    But judging from the posts here, it may not be a "common" idiom.

    (And I am not suggesting it is a /good/ idiom. It's not one I use
    myself, and I have "-Winit-self" in my list of standard warning
    flags because it is conceivable that I write "int a = a;" in error.
    But there are lots of idioms and common practices in C that I don't
    like personally.)


    As far as I understand it (and I hope to be corrected if I am
    wrong), "int a = a;" is not undefined behaviour as long as the
    implementation does not have trap values for "int". It simply
    leaves "a" as an unspecified value - just like "int a;" does. Thus
    it is not in any way "worse" than "int a;" as far as C semantics
    are concerned. Any difference is a matter of implementation - and
    the usual implementation effect is to disable "not initialised"
    warnings.

    It is in much the same category as "(void) x;", which is an idiom
    for skipping an "unused variable" or "unused parameter" warning.

    I would disagree with this last statement. (void)x is genuinely
    useful and has no ill side effects. 'int a = a;' is exactly
    the opposite - not useful and has potenial bad side effects.

    I concur except that I recommend using (void)&x rather than (void)x,
    because (void)&x is safer. If x is volatile qualified, for example,
    the expression (void)x actually does something, and must not be
    compiled away, whereas (void)&x does not have these properties.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Ros@invalid.invalid on Thu Mar 20 01:32:54 2025
    Rosario19 <Ros@invalid.invalid> writes:

    On Tue, 18 Mar 2025 23:52:20 -0700, Tim Rentsch wrote:

    (Kenny McCormack) writes:

    David Brown wrote:
    ...

    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    People would not normally write "int a = a;". It is used as a
    common idiom meaning "I know it is not clear to the compiler
    that the variable is always initialised before use, but /I/
    know it is - so disable the use-without-initialisation warnings
    for this variable". So it makes perfect sense for the compiler
    not to warn about it!

    An addle-brained view. Anyone who thinks that should be forcibly
    removed from any activity involving software development.

    Wouldn't it just be easier and clearer to write: int a = 0;
    and be done with it?

    There are two problems: one, the semantics are different; and
    two, the impression given of the author's intent is different.
    It's kind of like saying "isn't it just easier and clearer to
    write 'red' rather than 'yellow'?" Writing 'int a = 0;' might be
    better or it might be worse, depending on one's point of view,
    but it shouldn't be considered either more clear or less clear,
    because it isn't saying the same thing.

    int a=a;
    for me initialize "a" variable with a value the compiler found
    right as in

    int a;

    only possibly silence compiler warning for variable not
    initializated

    If you want to take it that way, there is nothing wrong with
    that.

    But it's a mistake to assume everyone else will also take it to
    mean the same thing that you do.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Chris M. Thomasson on Thu Mar 20 09:39:30 2025
    On 19/03/2025 22:29, Chris M. Thomasson wrote:

    The scares me a bit:
    _____________________
    #include <stdio.h>

    int main() {

        int a = 666;

        {
            // Humm... Odd to me...
            int a = a;

            printf("%d", a);
        }

        return 0;
    }

    Yes, that is an unfortunate consequence of the scoping in C - on the
    line "int a = a;", the new "a" is initialised with its own unspecified
    value, not with the value of the outer "a".

    If the scope of the new variable did not start until after the
    initialisation, then it would have allowed a number of possibilities
    that would be a lot more useful than the "disable warnings about
    uninitialised variables" effect or initialisers which refer to their own address. For example :

    int a = 123;
    {
    int a = a;
    // local copy that does not affect the outer one
    ...


    int a = 123;
    {
    long long int a = a;
    // Local copy that with expanded size
    ...

    for (int a = 0; a < 100; a++) {
    const int a = a;
    // "Lock" the loop index to catch errors

    As it is, you need to do something like :

    for (int a = 0; a < 100; a++) {
    const int _a = a;
    const int a = _a;
    // "Lock" the loop index to catch errors


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Thu Mar 20 11:59:10 2025
    On 20/03/2025 08:39, David Brown wrote:
    On 19/03/2025 22:29, Chris M. Thomasson wrote:

    The scares me a bit:
    _____________________
    #include <stdio.h>

    int main() {

         int a = 666;

         {
             // Humm... Odd to me...
             int a = a;

             printf("%d", a);
         }

         return 0;
    }

    Yes, that is an unfortunate consequence of the scoping in C - on the
    line "int a = a;", the new "a" is initialised with its own unspecified
    value, not with the value of the outer "a".

    So the inner 'a' wasn't supposed to mysteriously inherit the outer a's
    value? (Perhaps due to sharing the same location.) Since the compilers I
    tried just showed zero not 666.

    (Since this thread's subject was an alternative language, in that one it
    can be done like this, but with the first 'a' outside the function since
    there are no block scopes; the module is called 'test':

    int a = 666

    proc main =
    int a := test.a
    println a, test.a

    The outer 'a' needs that qualifier to access it, in scopes where it
    would be shadowed. Alternatively an alias can be created then that used instead:

    int a = 666
    int b @ a

    I don't know if any of these zero-run-time overhead methods are possible
    in C. Possibly a union, but that's only if you can define 'a' yourself,
    and is not an import for example. But then you have to permanently use
    the union 'qualifier'.)

    If the scope of the new variable did not start until after the initialisation, then it would have allowed a number of possibilities
    that would be a lot more useful than the "disable warnings about uninitialised variables" effect or initialisers which refer to their own address.  For example :

        int a = 123;
        {
            int a = a;
            // local copy that does not affect the outer one
        ...


        int a = 123;
        {
            long long int a = a;
            // Local copy that with expanded size
        ...

        for (int a = 0; a < 100; a++) {
            const int a = a;
            // "Lock" the loop index to catch errors

    As it is, you need to do something like :

        for (int a = 0; a < 100; a++) {
            const int _a = a;
            const int a = _a;
            // "Lock" the loop index to catch errors

    You mean locking the loop index so it can't be modified? On the same
    subject, that other language works like this:

    for a in 0..99 do
    a := 777 # not allowed

    Loop variables, if not already defined as variables, are automatically
    as read-only variables.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Thu Mar 20 15:46:33 2025
    On 20/03/2025 12:59, bart wrote:
    On 20/03/2025 08:39, David Brown wrote:
    On 19/03/2025 22:29, Chris M. Thomasson wrote:

    The scares me a bit:
    _____________________
    #include <stdio.h>

    int main() {

         int a = 666;

         {
             // Humm... Odd to me...
             int a = a;

             printf("%d", a);
         }

         return 0;
    }

    Yes, that is an unfortunate consequence of the scoping in C - on the
    line "int a = a;", the new "a" is initialised with its own unspecified
    value, not with the value of the outer "a".

    So the inner 'a' wasn't supposed to mysteriously inherit the outer a's
    value? (Perhaps due to sharing the same location.) Since the compilers I tried just showed zero not 666.

    No, the inner "a" is completely new and is initialised with itself. As
    Keith has pointed out, this is UB - but of course compilers can choose
    how to implement the code in question. gcc seems to pick "initialise to
    0" as a default when you write "int a;" and then read "a", and does the
    same for "int a = a;". Other compilers could choose to do something
    different, such as pick a register for "a" and leave the value in the
    register unchanged - in which case it might, by luck, pick up the value
    of the outer "a".


    If the scope of the new variable did not start until after the
    initialisation, then it would have allowed a number of possibilities
    that would be a lot more useful than the "disable warnings about
    uninitialised variables" effect or initialisers which refer to their
    own address.  For example :

         int a = 123;
         {
             int a = a;
             // local copy that does not affect the outer one
         ...


         int a = 123;
         {
             long long int a = a;
             // Local copy that with expanded size
         ...

         for (int a = 0; a < 100; a++) {
             const int a = a;
             // "Lock" the loop index to catch errors

    As it is, you need to do something like :

         for (int a = 0; a < 100; a++) {
             const int _a = a;
             const int a = _a;
             // "Lock" the loop index to catch errors

    You mean locking the loop index so it can't be modified?

    Yes.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Tim Rentsch on Thu Mar 20 15:57:48 2025
    On 20/03/2025 10:02, Tim Rentsch wrote:
    scott@slp53.sl.home (Scott Lurndal) writes:

    I would disagree with this last statement. (void)x is genuinely
    useful and has no ill side effects. 'int a = a;' is exactly
    the opposite - not useful and has potenial bad side effects.

    I concur except that I recommend using (void)&x rather than (void)x,
    because (void)&x is safer. If x is volatile qualified, for example,
    the expression (void)x actually does something, and must not be
    compiled away, whereas (void)&x does not have these properties.

    I would recommend knowing which variables are volatile and which are
    not, so that the issue does not arise.

    Casting a volatile variable to void does "something", but what that
    "something" is is implementation-defined and can vary between compilers.
    Doing things to volatiles other than clear, simple reads or writes is
    a risk - the semantics are not fully defined in the C standards, implementations vary, and it is not at all uncommon for implementations
    to be inconsistent or buggy in that area. This is why C++ has
    deprecated many uses of volatile objects. So if you actually want to
    read a volatile variable but ignore the results (as you might well want
    to do for hardware device registers), it's best to do :

    auto dummy = volatile_var;
    (void) dummy;

    rather than

    (void) volatile_var;

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to bart on Thu Mar 20 22:55:22 2025
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 15:10, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 12:17, Waldek Hebisch wrote:

    I see. So your feature conflicts with C feature "variable which is
    initialized at declaration time is always used initialized".

    That doesn't happen here:

    int a = a;

    gcc (with no extra options) tcc and bcc both put some undefined value in a.

    gcc won't warn until you say '-Wextra', and then only for:

    int a = a + 1;

    Well, it is rather easy to see if variable is used within its
    own initialization, so practically it is minor gap. Of course,
    there is problem with C standard: IIUC depending on rest of
    the code declarations as above are merely undefined behaviour
    or even produce unspecified value. So C compiler is
    forbidden to stop compilation are report compile time error.

    However, your language has no constrains that C has, so you
    could do better.

    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to bart on Thu Mar 20 22:38:02 2025
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 15:10, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 12:17, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    This is the document I produced:

    https://github.com/sal55/langs/blob/master/MFeatures.md

    A couple of more substantial demo programs are here:
    https://github.com/sal55/langs/tree/master/MExamples

    (The bignum.m file was ported - by hand - to the bignum.c version that I >>>>> posted recently.)

    Looking at features, can you say if the program below works?
    And if it works, what is retrun value of foo? "Equvalent" can
    be written in C, but in C you have to keep sane order.


    There were some tweaks needed; it indicates some basic info missing from >>> my write-up! (For example, that the function call needs to be bar() not
    bar; 'const' is only for compile-time expressions; and that C's 'const'
    doesn't exist - it only briefly mentions an attempt at 'let'.)

    The revised code is shown below, with what I assumed were your
    intentions.

    Well, my intentions beter correspond to the C version below:

    int foo() {
    const int c = c1(10);
    const int b = c + c2(2);
    const int a = b+c3(c);
    bar();
    baz();
    return c;
    }


    In this case, just write it like that, and only adjust it for the
    somewhat different syntax:

    func foo:int =
    let int c := c1(10)
    let int b := c + c2(2)
    let int a := b+c3(c)
    bar()
    baz()
    return c
    end

    In your description you wrote that declarations can be written
    "out of order" and compiler will rearrange them in correct
    order. That looked like great opportunity to write obfuscated
    code. As you explained, it works differently, but I think
    already the fixed version of code I gave shows potential.
    And the following seem to satisfy your restriction that
    'const' is compile time constant and what happens is
    puzzling to the reader (better than goto-s used to confuse
    control flow):

    func foo:int =
    const a = b + c
    let int cc := c1(a)
    const b = c + 2
    let int bb := c2(b) + cc
    const c = 10
    bb + c
    end

    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Waldek Hebisch on Thu Mar 20 23:45:51 2025
    On 2025-03-20, Waldek Hebisch <antispam@fricas.org> wrote:
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 15:10, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 12:17, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    This is the document I produced:

    https://github.com/sal55/langs/blob/master/MFeatures.md

    A couple of more substantial demo programs are here:
    https://github.com/sal55/langs/tree/master/MExamples

    (The bignum.m file was ported - by hand - to the bignum.c version that I >>>>>> posted recently.)

    Looking at features, can you say if the program below works?
    And if it works, what is retrun value of foo? "Equvalent" can
    be written in C, but in C you have to keep sane order.


    There were some tweaks needed; it indicates some basic info missing from >>>> my write-up! (For example, that the function call needs to be bar() not >>>> bar; 'const' is only for compile-time expressions; and that C's 'const' >>>> doesn't exist - it only briefly mentions an attempt at 'let'.)

    The revised code is shown below, with what I assumed were your
    intentions.

    Well, my intentions beter correspond to the C version below:

    int foo() {
    const int c = c1(10);
    const int b = c + c2(2);
    const int a = b+c3(c);
    bar();
    baz();
    return c;
    }


    In this case, just write it like that, and only adjust it for the
    somewhat different syntax:

    func foo:int =
    let int c := c1(10)
    let int b := c + c2(2)
    let int a := b+c3(c)
    bar()
    baz()
    return c
    end

    In your description you wrote that declarations can be written
    "out of order" and compiler will rearrange them in correct
    order. That looked like great opportunity to write obfuscated
    code.

    I made a language feature like that: mlet.

    https://www.nongnu.org/txr/txr-manpage.html#N-2B3072E9

    This allows for circular references in order to support
    the construction of lazy objects:

    (mlet ((a (lcons 1 b))
    (b (lcons 0 a)))
    (take 20 a))
    (1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0)

    If we use the regular cons function, rather than the
    lcons lazy cons macro operator:

    (mlet ((a (cons 1 b))
    (b (cons 0 a)))
    (take 20 a))
    ** expr-1:1: force: recursion forcing delayed form (cons 1 b) (expr-1:1)

    When there isn't circularity, the expressions can be in
    any order; the lazy machinery will force the evaluation
    of everything in the correct order:

    (mlet ((x (+ y 3))
    (z (+ x 1))
    (y 4))
    (+ z 4))
    12

    First y gets 4, so (+ y 3) can initialize x to 7,
    after which z can take (+ x 1) to get 8. Then
    the body evaluates (+ z 4) to 12.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Waldek Hebisch on Fri Mar 21 00:33:11 2025
    On 20/03/2025 22:38, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 15:10, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:
    On 18/03/2025 12:17, Waldek Hebisch wrote:
    bart <bc@freeuk.com> wrote:

    This is the document I produced:

    https://github.com/sal55/langs/blob/master/MFeatures.md

    A couple of more substantial demo programs are here:
    https://github.com/sal55/langs/tree/master/MExamples

    (The bignum.m file was ported - by hand - to the bignum.c version that I >>>>>> posted recently.)

    Looking at features, can you say if the program below works?
    And if it works, what is retrun value of foo? "Equvalent" can
    be written in C, but in C you have to keep sane order.


    There were some tweaks needed; it indicates some basic info missing from >>>> my write-up! (For example, that the function call needs to be bar() not >>>> bar; 'const' is only for compile-time expressions; and that C's 'const' >>>> doesn't exist - it only briefly mentions an attempt at 'let'.)

    The revised code is shown below, with what I assumed were your
    intentions.

    Well, my intentions beter correspond to the C version below:

    int foo() {
    const int c = c1(10);
    const int b = c + c2(2);
    const int a = b+c3(c);
    bar();
    baz();
    return c;
    }


    In this case, just write it like that, and only adjust it for the
    somewhat different syntax:

    func foo:int =
    let int c := c1(10)
    let int b := c + c2(2)
    let int a := b+c3(c)
    bar()
    baz()
    return c
    end

    In your description you wrote that declarations can be written
    "out of order" and compiler will rearrange them in correct
    order.

    I made a decision to allow out-of-order definitions for all names, and I followed through with that. That is useful for:

    * Function definitions
    * Types and records (usually mutually referential ones)
    * Named compile-time-constants
    * Enumerations
    * Macros
    * FFI Import declarations
    * Module-level variables

    So, you just don't need to worry about it. Inside the top-level scope of
    a module for example, such a mix of definitions all exist
    simultaneously; there is no ordering.

    All the above are defined using '=', which is a compile-time concept
    (variables either are not initialised so are all-zeros, or use '=' too
    at module scope).

    However, you've picked on local variables inside a function, where assignments/initialisations are done with ':=', a runtime operation.
    Hence there is a ordering to those assignments, even if the variable
    /names/ that are defined exist function-wide and are unordered with
    respect to other names in the scope.


    That looked like great opportunity to write obfuscated
    code.

    Sorry, it's not quite up to the standard of C, where:

    * There are unlimited numbers of block scopes within each function

    * So the same name A can be reused in each one, with a different type

    * Scopes can start part-way through a block, so two different A's can
    co-exist within the block

    * There are parallel struct/enum tag and label namespaces, so that A can
    also be a struct A or enum A or A: in the same scope:

    int A; {++A; struct A {int A;} A; A: A=A; goto A;}

    * If that is not quite enough, you can define parallel instances of A
    but in lower case 'a'.

    I haven't even had to call upon macros for extra obfuscation!

    As you explained, it works differently, but I think
    already the fixed version of code I gave shows potential.
    And the following seem to satisfy your restriction that
    'const' is compile time constant and what happens is
    puzzling to the reader (better than goto-s used to confuse
    control flow):

    func foo:int =
    const a = b + c
    let int cc := c1(a)
    const b = c + 2
    let int bb := c2(b) + cc
    const c = 10
    bb + c
    end

    Here's an actual use-case from an older C compiler project. It's some
    lines from a table of type-enums with parallel arrays:

    (tschar, "schar", 8, 1, tsint),
    (tsshort, "short", 16, 1, tsint),
    (tsint, "int", 32, 1, 0, ),
    (tsllong, "llong", 64, 1, 0, ),

    The left column is enums used to denote C types inside the project.

    The last column starting 'tsint' specifies what narrow types expand to
    in an expression.

    Notice that 'tsint' is an enum name which is itself not specified until
    a couple of lines later. This is out-of-order definitions in action.

    What obfuscations are needed in C to achieve the same? Maybe X-macros,
    or defining discrete arrays which need to be kept in sync. Maybe all
    sorts of other workarounds.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Kaz Kylheku on Fri Mar 21 00:56:34 2025
    On 20/03/2025 23:45, Kaz Kylheku wrote:
    On 2025-03-20, Waldek Hebisch <antispam@fricas.org> wrote:
    bart <bc@freeuk.com> wrote:

    In this case, just write it like that, and only adjust it for the
    somewhat different syntax:

    func foo:int =
    let int c := c1(10)
    let int b := c + c2(2)
    let int a := b+c3(c)
    bar()
    baz()
    return c
    end

    >> In your description you wrote that declarations can be written
    "out of order" and compiler will rearrange them in correct
    order. That looked like great opportunity to write obfuscated
    code.

    I made a language feature like that: mlet.

    https://www.nongnu.org/txr/txr-manpage.html#N-2B3072E9

    This allows for circular references in order to support
    the construction of lazy objects:

    (mlet ((a (lcons 1 b))
    (b (lcons 0 a)))
    (take 20 a))
    (1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0)

    I don't understand what's going on above; the example here is a bit
    clearer, other than that z at the end:

    (mlet ((x (+ y 1))
    (y (+ z 1))
    (z (+ x 1)))
    z)

    But this looks like something that goes on at runtime. In the language
    above, it's all dealt with at compile time. If I create a similar example:

    const x = y + 1,
    y = z + 1,
    z = x + 1

    then it is the compiler that reports a circular reference.

    Otherwise, in my dynamic (and non-lazy) language, circular references
    are allowed at runtime, but it is object references rather than names:

    a ::= (1,2,3) # create two short lists (::= makes a mutable copy)
    b ::= (4,5,6)

    a &:= b # append each to the other (concatenate is
    b &:= a # well-behaved)

    println a
    println b

    Shows two now infinite lists:

    (1,2,3,(4,5,6,(1,2,3,(4,5,6,...))))
    (4,5,6,(1,2,3,(4,5,6,(1,2,3,...))))

    (An attempt to deep-copy one of those will end badly.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Fri Mar 21 17:47:24 2025
    On 2025-03-21, bart <bc@freeuk.com> wrote:
    On 20/03/2025 23:45, Kaz Kylheku wrote:
    On 2025-03-20, Waldek Hebisch <antispam@fricas.org> wrote:
    bart <bc@freeuk.com> wrote:

    In this case, just write it like that, and only adjust it for the
    somewhat different syntax:

    func foo:int =
    let int c := c1(10)
    let int b := c + c2(2)
    let int a := b+c3(c)
    bar()
    baz()
    return c
    end

    >> In your description you wrote that declarations can be written
    "out of order" and compiler will rearrange them in correct
    order. That looked like great opportunity to write obfuscated
    code.

    I made a language feature like that: mlet.

    https://www.nongnu.org/txr/txr-manpage.html#N-2B3072E9

    This allows for circular references in order to support
    the construction of lazy objects:

    (mlet ((a (lcons 1 b))
    (b (lcons 0 a)))
    (take 20 a))
    (1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0)

    I don't understand what's going on above; the example here is a bit
    clearer, other than that z at the end:

    What's going on is that

    1. A variable that is not accessed is not initialized at all.
    When a variable is used for the first time (dynamically;
    determined at run time as you correcly observe) the
    initializing expression is evaluated then. Here, we don't
    see the (print 42) side effedt in the case where x is not
    used:

    1> (mlet ((x (prinl 42))) x)
    42
    42
    2> (mlet ((x (prinl 42))))
    nil

    2. lcons is also a lazy construct; it is not a function but
    a macro operator. It constructs and returns a lazy cons
    cell which is associated with a lambda function that will
    fill the car and cdr of the lazy cons cell when either of
    those fields are accessed for the first time.
    So (lcons 1 b) returns a lazy cons which is uninitialized.
    When we access it, 1 is put into the car, and b is evaluated
    and put into the cdr.

    3. The first thing to be evaluated is the body expression (take 20 a).
    This causes (lcons 1 b) to be evaluated and a to take on that
    value. The take function will traverse into that cell, triggering
    b's initializer (lcons 0 a) being evaluated.
    When the take function steps into that second cell, triggering
    its lazy initialization, variable a already has a value,
    pointing to the first cell. So the circular list is closed.
    take then just keeps walking the finished circular list, until
    it obtains 20 items.

    (mlet ((x (+ y 1))
    (y (+ z 1))
    (z (+ x 1)))
    z)

    But this looks like something that goes on at runtime. In the language
    above, it's all dealt with at compile time. If I create a similar example:

    Serious functional languages which are single-mindedly dedicated to lazy semantics will hoist a lot of this kind of processing to compile time.

    I could make a non-lazy binding macro which determines the dependencies among the expressions, detects and diagnoses cycles, and then emits a regular let based on a topological sort of the dependencies.

    The tools are there; there is an API by which a macro can ask what are the free variable references emanating from a piece of code, so we can know exactly which of the variables in the circular let construct are being referenced by which initializing expressions, and build a graph from that.

    There is just not use for such a thing. Programs already require us to jump backwards and forwards to understand the flow due to the presence of functiond definitions, and looping constructs; we don't need that at the statement level.

    mlet allows any order because that's a side effect of handling the mutually referencing lazy definitions, not because that's the motivating use case.

    const x = y + 1,
    y = z + 1,
    z = x + 1

    then it is the compiler that reports a circular reference.

    Otherwise, in my dynamic (and non-lazy) language, circular references
    are allowed at runtime, but it is object references rather than names:

    a ::= (1,2,3) # create two short lists (::= makes a mutable copy)
    b ::= (4,5,6)

    a &:= b # append each to the other (concatenate is
    b &:= a # well-behaved)

    So, if you had a category of list cells that are lazy, you could
    bring about this circularity without ever perpetrating a mutating
    assignment. (Because it's hidden in the implementation: when the lazy
    cell is accessed, its fields are de facto assigned then, but in the abstract semantics, it's understood as not being initialized.)

    1> (let (a b)
    (set a (lcons 1 b))
    (set b (lcons 0 a))
    (take 20 a))
    (1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0)

    Here we still have assignments to bring about the circularity, but the assignments are just of lexical variables, not of the list structure.

    The mlet solves the problem of hiding the variable assignments,
    in its own way.

    There is a cheaper way to solve the problem for the above case;
    we can have a "letrec" construct (similar to what exists in Scheme) which literally does what we did above; i.e. one which takes:

    (letrec ((a (lcons 1 b))
    (b (lcons 0 a))
    ...body...)

    and writes, effectively, this code:

    (let (a b)
    (set a (lcons 1 b))
    (set b (lcons 0 a))
    ...body...)

    that is to say, the initializing forms have all the variables in scope, and are evaluated from left to right. An earlier initform evaluating a later variable will see a nil value. But here the lcons forms are lazy, and so do not evaluate the variables. In other words, we don't need the laziness of mlet; lcons is enough.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Kaz Kylheku on Sat Mar 22 07:12:58 2025
    Kaz Kylheku <643-408-1753@kylheku.com> writes:

    On 2025-03-21, bart <bc@freeuk.com> wrote:

    On 20/03/2025 23:45, Kaz Kylheku wrote:

    On 2025-03-20, Waldek Hebisch <antispam@fricas.org> wrote:

    bart <bc@freeuk.com> wrote:

    In this case, just write it like that, and only adjust it for the
    somewhat different syntax:

    func foo:int =
    let int c := c1(10)
    let int b := c + c2(2)
    let int a := b+c3(c)
    bar()
    baz()
    return c
    end

    >> In your description you wrote that declarations can be written

    "out of order" and compiler will rearrange them in correct
    order. That looked like great opportunity to write obfuscated
    code.

    I made a language feature like that: mlet.

    https://www.nongnu.org/txr/txr-manpage.html#N-2B3072E9

    This allows for circular references in order to support
    the construction of lazy objects:

    (mlet ((a (lcons 1 b))
    (b (lcons 0 a)))
    (take 20 a))
    (1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0)

    I don't understand what's going on above; the example here is a
    bit clearer, other than that z at the end:

    What's going on is that [...]

    Just a short reminder that this is comp.lang.c, and nothing about
    any of the discussions above has anything to do with C.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to Keith Thompson on Sat Mar 22 14:37:34 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    antispam@fricas.org (Waldek Hebisch) writes:
    [...]
    Well, it is rather easy to see if variable is used within its
    own initialization, so practically it is minor gap. Of course,
    there is problem with C standard: IIUC depending on rest of
    the code declarations as above are merely undefined behaviour
    or even produce unspecified value. So C compiler is
    forbidden to stop compilation are report compile time error.

    Valid responses to undefined behavior include "terminating a translation
    or execution (with the issuance of a diagnostic message)". In other
    words, if a compiler is able to prove that a program has undefined
    behavior (that will occur on each execution), it can reject it at
    compile time.

    This was probably subject to previous disscussion here, IIRC
    some posters here claimed that even in such case implementation
    is supposed to produce an executable. However, certainly
    implementation must accept the program when code that would
    exhibit undefined behaviour is not executed. And in practice
    when using separate compilation compiler normally is not
    able to decide if a function will be called or not (and even
    when whole program is available compiler still have halting
    problem to solve). So cases when compiler is allowed to report
    compilation error are quite limite in practice.

    So, putting a constraint on self reference in initialization
    would improve error detection in C compilers. And of course
    languages that what to be better than C should avoid C
    mistake.

    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Waldek Hebisch on Sat Mar 22 11:41:23 2025
    On 3/22/25 10:37, Waldek Hebisch wrote:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    ...
    Valid responses to undefined behavior include "terminating a translation
    or execution (with the issuance of a diagnostic message)". In other
    words, if a compiler is able to prove that a program has undefined
    behavior (that will occur on each execution), it can reject it at
    compile time.

    This was probably subject to previous disscussion here, IIRC
    some posters here claimed that even in such case implementation
    is supposed to produce an executable.

    There is no such requirement. Could you identify who made such a claim,
    when, with what arguments? My newserver's archives only go back three
    months, and if the claim was made by somebody I've got killfiled, I
    won't be able to see it even during that time period. Google Groups
    stopped archiving new messages quite a while ago. Therefore, it might be
    best to quote the relevant text, rather than merely identifying it.

    However, certainly
    implementation must accept the program when code that would
    exhibit undefined behaviour is not executed. And in practice
    when using separate compilation compiler normally is not
    able to decide if a function will be called or not (and even
    when whole program is available compiler still have halting
    problem to solve). So cases when compiler is allowed to report
    compilation error are quite limite in practice.

    Keep in mind that the Halting problem is difficult only because the
    decider must handle every case. Compilers are, in practice, able to
    detect many cases of undefined behavior, even though they are not
    capable of detecting them all.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to James Kuyper on Sat Mar 22 16:52:58 2025
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 3/22/25 10:37, Waldek Hebisch wrote:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    ...
    Valid responses to undefined behavior include "terminating a translation >>> or execution (with the issuance of a diagnostic message)". In other
    words, if a compiler is able to prove that a program has undefined
    behavior (that will occur on each execution), it can reject it at
    compile time.

    This was probably subject to previous disscussion here, IIRC
    some posters here claimed that even in such case implementation
    is supposed to produce an executable.

    There is no such requirement. Could you identify who made such a claim,
    when, with what arguments? My newserver's archives only go back three
    months, and if the claim was made by somebody I've got killfiled, I
    won't be able to see it even during that time period. Google Groups
    stopped archiving new messages quite a while ago. Therefore, it might be
    best to quote the relevant text, rather than merely identifying it.

    Sorry, is would be quite a lot of work to find relevant messages.

    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Waldek Hebisch on Sat Mar 22 20:12:52 2025
    On 3/22/25 12:52, Waldek Hebisch wrote:
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 3/22/25 10:37, Waldek Hebisch wrote:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    ...
    Valid responses to undefined behavior include "terminating a translation >>>> or execution (with the issuance of a diagnostic message)". In other
    words, if a compiler is able to prove that a program has undefined
    behavior (that will occur on each execution), it can reject it at
    compile time.

    This was probably subject to previous disscussion here, IIRC
    some posters here claimed that even in such case implementation
    is supposed to produce an executable.

    There is no such requirement. Could you identify who made such a claim,
    when, with what arguments? My newserver's archives only go back three
    months, and if the claim was made by somebody I've got killfiled, I
    won't be able to see it even during that time period. Google Groups
    stopped archiving new messages quite a while ago. Therefore, it might be
    best to quote the relevant text, rather than merely identifying it.

    Sorry, is would be quite a lot of work to find relevant messages.

    Then I will go ahead with the assumption that those arguments are
    invalid until they are identfied.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Sun Apr 27 11:53:05 2025
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    antispam@fricas.org (Waldek Hebisch) writes:
    [...]

    Well, it is rather easy to see if variable is used within its
    own initialization, so practically it is minor gap. Of course,
    there is problem with C standard: IIUC depending on rest of
    the code declarations as above are merely undefined behaviour
    or even produce unspecified value. So C compiler is
    forbidden to stop compilation are report compile time error.

    Valid responses to undefined behavior include "terminating a translation
    or execution (with the issuance of a diagnostic message)".

    That's true, but doing so is allowed only if the circumstances
    of undefined behavior have occurred. In the case of compiling
    a declaration such as

    int a = a;

    no undefined behavior has as yet occurred.

    In other
    words, if a compiler is able to prove that a program has undefined
    behavior (that will occur on each execution), it can reject it at
    compile time.

    The program can be rejected, but not because of the rule about
    terminating a translation. The program can be rejected because
    the program is not strictly conforming, and implementations are
    not required to accept programs that are not strictly conforming.

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