• Re: technology discussion =?UTF-8?Q?=E2=86=92?= does the world need a "

    From Kaz Kylheku@21:1/5 to James Kuyper on Mon Jul 8 00:02:39 2024
    On 2024-07-07, James Kuyper <[email protected]> wrote:
    On 7/7/24 16:10, BGB wrote:
    On 7/7/2024 9:03 AM, James Kuyper wrote:
    On 7/7/24 00:55, BGB wrote:
    On 7/6/2024 5:38 PM, Keith Thompson wrote:
    ...
    No, there is no implicitly defined pointer.
    ...
    This implicit pointer need not exist at a location in memory...

    Which is why C doesn't give you access to it's location in memory -
    something you complained about earlier.

    I don't think I was claiming that one should have direct access to its
    location or value within the language, rather that their existence and
    behaviors could be acknowledged in the language design (for a "not
    quite C" language).

    I think that the existence of an implicit pointer would be a bad thing
    to acknowledge, given that the language doesn't require that it exist,
    and typical implementations don't use them. From what I understand, the
    fact that your implementation does have implicit pointers makes it a rarity.

    Ritchie's B language had arrays which contained a pointer to their
    first element. Via a hack, it was possible to relocate an array.

    In C, such a thing is not simply not required; it is ruled out
    by the detailed semantic description of arrays.

    The entire representation of an array of size N elements of type
    T is contained in the memory block that is sizeo(T)*N bytes wide.

    If you copy that block, you have a fully functional copy of the array.
    No extra pointer needs to be set up with the correct value.

    Furthermore, to dynamically allocate an array, you need only
    provide sizeof(T)*N bytes of storage, and not a bit more.

    There is simply nowhere in the representation of an array where
    a pointer could hide that is part of the representation.

    Code that manipulates arrays can be translated into something that
    calculates a pointer. So a pointer can exist at run time, in a transient
    way, perhaps in a register. That register can even be spilled into
    memory. However, that's just part of the state of an evolving
    calculation, not part of the representation of the array.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @[email protected]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Tue Jul 9 18:39:13 2024
    On Tue, 9 Jul 2024 16:31:30 +0200
    David Brown <[email protected]> wrote:

    On 08/07/2024 19:39, BGB wrote:
    On 7/7/2024 11:28 PM, James Kuyper wrote:
    On 7/7/24 20:02, Kaz Kylheku wrote:
    ...


    I see no point in having implicit pointers, but I don't believe
    that they are prohibited.


    They mostly exist in a "sort of simpler to implement the compiler
    this way" sense.

    In the implicit pointer case, the compiler just treats it as-if it
    were an explicit pointer. In this case, both are basically treated
    as being roughly equivalent at the IR levels.

    And, most of the code-generation stage doesn't need separate
    handling for arrays and pointers, but can use combined
    "ArrayOrPointer" handling or similar.

    It had all seemed "obvious enough".




    Similar reasoning for passing structs by-reference in the ABI:
      Pass by reference is easy to implement;
      In place copying and decomposing into registers, kinda bad.

    Though, this one seems to be a common point of divergence between
    "SysV" and "Microsoft" ABIs. Sometimes a target will have an ABI
    defined, and the MS version was almost the same, just typically
    differing in that it passes structs by reference and provides a
    spill space for register arguments.


    I don't think it is helpful that you keep mixing /logical/ terms with /implementation/ terms.

    In C, there is no "pass by reference" or "return by reference". It
    is all done by value. Even when you use pointer arguments or return
    types, you are passing or returning pointer values. C programmers
    use pointers to get the effect of passing by reference, but in C you
    use pointers to be explicit about references.

    Structs in C are passed by value, and returned by value. Not by
    reference.

    The C standards don't say how passing structs around by value is to
    be implemented - that is hidden from the programmer. Usually ABI's
    (which are also hidden from the programmer) specify the
    implementation details, but some ABI's are weak in that area.
    Generally, structs up to a certain size or complexity are passed in
    registers while bigger or more advanced types are passed via
    addresses (pointing to stack areas) in registers or the stack, just
    like any other bigger types. This is not "pass by reference" as far
    as the C programming is concerned - but you could well call it that
    at the assembly level. Where the line between "passing in registers"
    and "passing via addresses to space on the stack" is drawn, is
    entirely up to the compiler implementation and any ABI requirements.
    Some simpler compilers will pass all structs via addresses, no matter
    how simple they are, while others will aim to use registers whenever possible.


    So if you have these structs and declarations :

    struct small { uint16_t a; uint16_t b; };
    struct big { uint32_t xs[10]; };

    struct small foos(struct small y);
    struct big foob(struct big y);

    Then compilers will typically implement "x = foos(y)" as though it
    were:

    extern uint32_t foos(uint32_t ab);
    uint32_t _1 = foos(y.a << 16) | (y.b);
    struct small x = { _1 >> 16, _1 & 0xffff };

    And they will typically implement "x = foosb(y)" as though it were:

    extern void foob(struct big * ret, const struct big * xs);
    struct big x;
    foob(&x, &y);


    It depends on the ABI. Newer ABIs tend to work like that. Older ABIs
    often copy the [big] structure to parameters area on callie's stack.
    With 16 or more registers I see no obvious performance advantage to
    either method. The preference of newer ABIs appears to be a matter of
    fashion.


    This is not, as you wrote somewhere, something peculiar to MSVC - it
    is the technique used by virtually every C compiler, except perhaps
    for outdated brain-dead 8-bit microcontrollers that have difficulty
    handling data on a stack.

    And it is not really "pass by reference" or "implicit pointers", it
    is just passing addresses around behind the scenes in the
    implementation.






    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Tue Jul 9 18:54:06 2024
    On Tue, 9 Jul 2024 16:37:31 +0200
    David Brown <[email protected]> wrote:

    On 06/07/2024 21:33, BGB wrote:

    In my compiler (BGBCC), such an internal pointer exists for arrays
    and structures in the local stack frame.

    No separate pointer exists inside of things like structs, where, as
    can be noted, the array exists at a fixed size and location.


    So, eg:
      void Foo()
      {
         int a[100];
         ...
      }

    There is both the space for 100 integers reserved in the stack
    frame, and a variable 'a' which exists as an implicit pointer to
    that location.


    But, say:
      void Foo()
      {
         int a[8192];
         ...
      }

    There is no space reserved on the stack, and the array is instead allocated dynamically (from the heap). In this case, the "a"
    variable exists as a pointer to that location in memory.

    Similar treatment also applies to structs.



    The C standard does not require a stack or say how local data is implemented, it just gives rules for the scope and lifetime of
    locals. However, I would be surprised and shocked to find a compiler
    I was using allocate local data on the heap in some manner. If I
    have an array as local data, it is with the expectation that it is
    allocated and freed trivially (an add or subtract to the stack
    pointer, typically combined with any other stack frame). If I want
    something on the heap, I will use malloc and put it on the heap.

    Such an implementation as yours is not, I think, against the C
    standards
    - but IMHO it is very much against C philosophy.


    I wouldn't mind if my ABI/compiler allocates all big local objects
    together with all local VLA either on separate secondary stack or even
    on heap. Such strategy will improve locality of reference for primary
    stack. So, despite higher management overhead, it could sometimes be advantageous even for performance.
    The main advantage however is not performance, but reducing the
    severity of damage caused by buffer overrun bugs.

    Although if "security" is a primary concern then one would want
    stricter policy than the one outlined above. I.e. not only big objects,
    but small object as well should be allocated away from primary stack as
    long as their address participate in pointer arithmetic that can't be
    proven safe by static analysis.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Michael S on Tue Jul 9 16:20:59 2024
    Michael S <[email protected]> writes:
    On Tue, 9 Jul 2024 16:31:30 +0200
    David Brown <[email protected]> wrote:


    So if you have these structs and declarations :
    =20
    struct small { uint16_t a; uint16_t b; };
    struct big { uint32_t xs[10]; };
    =20
    struct small foos(struct small y);
    struct big foob(struct big y);
    =20
    Then compilers will typically implement "x =3D foos(y)" as though it
    were:
    =20
    extern uint32_t foos(uint32_t ab);
    uint32_t _1 =3D foos(y.a << 16) | (y.b);
    struct small x =3D { _1 >> 16, _1 & 0xffff };
    =20
    And they will typically implement "x =3D foosb(y)" as though it were:
    =20
    extern void foob(struct big * ret, const struct big * xs);
    struct big x;
    foob(&x, &y);


    It depends on the ABI. Newer ABIs tend to work like that. Older ABIs
    often copy the [big] structure to parameters area on callie's stack.
    With 16 or more registers I see no obvious performance advantage to
    either method. The preference of newer ABIs appears to be a matter of >fashion.

    It also depends on whether the callee modifies the structure. From
    the System V i386 processor Specific ABI (dated 1997):

    As described in the data representation section, structures and unions can have
    byte, halfword, or word alignment, depending on the constituents. An
    argument's size is increased, if necessary, to make it a multiple of words. This
    may require tail padding, depending on the size of the argument. To ensure that
    data in the stack is properly aligned, the stack pointer should always point to a
    word boundary. Structure and union arguments are pushed onto the stack in the
    same manner as integral arguments, described above. This provides call-by-value
    semantics, letting the called function modify its arguments without affecting the
    calling function's object.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Tue Jul 9 22:32:45 2024
    On 2024-07-09, bart <[email protected]> wrote:
    On 09/07/2024 16:58, Ben Bacarisse wrote:
    bart <[email protected]> writes:

    Arrays are passed by reference:

    void F(int a[20]) {}

    int main(void) {
    int x[20];
    F(x);
    }

    This is the sort of thing that bad tutors say to students so that they
    never learn C properly. All parameter passing in C is by value. All of
    it. You just have to know (a) what the syntax means and (b) what values
    get passed.

    The end result is that a parameter declared with value-array syntax is
    passed using a reference rather than by value.

    And it does so because the language says, not because the ABI requires
    it. A 2-byte array is also passed by reference.

    In C, arrays are not passed to functions, period.

    Therefore ABIs do not say anything about array parameters,
    (or if they do, it's not in relation to C).

    An array can be wrapped in a struct: struct a { int a[42] }.
    /That/ can be passed to a function, in the only way that C supports,
    which is by value.

    At the ABI level, passing of structs may be by address or copy,
    and it may be dependent on the size. A small structure an be passed
    as a parameter, or couple of parameters, which may be registers.
    That's an implementation detail, all corresponding to "pass by value".

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @[email protected]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Wed Jul 10 03:19:10 2024
    On 2024-07-09, bart <[email protected]> wrote:
    On 09/07/2024 23:32, Kaz Kylheku wrote:
    On 2024-07-09, bart <[email protected]> wrote:
    On 09/07/2024 16:58, Ben Bacarisse wrote:
    bart <[email protected]> writes:

    Arrays are passed by reference:

    void F(int a[20]) {}

    int main(void) {
    int x[20];
    F(x);
    }

    This is the sort of thing that bad tutors say to students so that they >>>> never learn C properly. All parameter passing in C is by value. All of >>>> it. You just have to know (a) what the syntax means and (b) what values >>>> get passed.

    The end result is that a parameter declared with value-array syntax is
    passed using a reference rather than by value.

    And it does so because the language says, not because the ABI requires
    it. A 2-byte array is also passed by reference.

    In C, arrays are not passed to functions, period.

    Arrays can be passed by explicit reference:

    The C term for "explicit reference" is "pointer".

    C has neither "pass by pointer" nor "pass by explicit reference"; it has pointers passed by value.

    Pass by reference/pointer looks like this:

    void f(var int x)
    {
    x++:
    }

    int main(void)
    {
    int x = 42;
    f(x);
    // x is now 43
    }

    That's like a var parameter in Pascal or C++ references (where our
    fantasy syntax looks like void f(int &x).

    Pass by reference means the callee can assign to the parameter
    and the caller's object changes. (Unless it's some kind of constant
    reference or something.)

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @[email protected]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to James Kuyper on Wed Jul 10 06:05:14 2024
    On 2024-07-10, James Kuyper <[email protected]> wrote:
    On 7/10/24 00:29, Lawrence D'Oliveiro wrote:
    On Sat, 06 Jul 2024 15:38:14 -0700, Keith Thompson wrote:
    ...
    If you evaluate the expression `array_object` in most contexts, it's
    implicitly converted to a pointer *value*, pointing to the 0th element
    of the array object. There is still no implicit pointer object.

    The OP said “pointer”, not “pointer object” or “pointer value”. Not sure
    what hair you are trying to split here.

    BGB referred to it as an "implicitly declared" pointer. You can declare objects in C, but not values. An object has a location in addressable
    memory where it is stored, a value need not exist anywhere in
    addressable memory.

    Right. But language features can use hidden variables.

    In every implementation that I'm sufficiently familiar with, no memory
    is set aside to store such a pointer object.

    Even if the high level code generation declares such a hidden
    variable, as in

    int a[42];
    int *$_ptr_a = a; // generated by compiler
    // perhaps as an AST node rather than source

    it could end up optimized away, like any other variable. Since the
    variable is not visible to the program, no assignment to its value
    will occur (unless the generated code does that). If no assignment
    to it occurs, the optimization can just treat it as an alias for a,
    and substitute every occurrence of $_ptr_a with a. (Raising the
    question why the code generator didn't do that itself; it could
    be a remnant from an ancient verson of the compiler that wasn't well
    optimized. Then the optimizer came along, taking away the motivation
    to fix something in the front that is taken care of by it.)

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @[email protected]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Lawrence D'Oliveiro on Wed Jul 10 11:27:09 2024
    On 2024-07-10, Lawrence D'Oliveiro <[email protected]d> wrote:
    On Sat, 06 Jul 2024 15:23:47 -0700, Keith Thompson wrote:

    Lawrence D'Oliveiro <[email protected]d> writes:

    On Fri, 05 Jul 2024 11:46:38 -0700, Keith Thompson wrote:

    No, arrays are not pointers.

    Except array indexing is designed to be indistinguishable from pointer
    arithmetic.

    No, arrays are not pointers.

    Can you point out any situation where this construct

    &a[b]

    might be valid, but this

    (a + b)

    (with the same declarations of “a” and “b”) might not?

    Miller Genuine Daft at work again.

    a[b] /means/ *(a + (b)) so your reasoning is circular.

    Arrays are not pointers. Given arrays a and b of equal size:

    - sizeof a is not sizeof &[0] other than by coincidence

    - &a is not &a[0] -- different type

    - a = b is invalid -- arrays are not modifiable lvalues

    - arrays cannot be passed to functions nor returned;
    pointers can.

    - int (f[3])(void) { }, function returning array of 3 int,
    is a constraint violation.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @[email protected]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Tim Rentsch on Wed Jul 10 20:14:54 2024
    On Wed, 10 Jul 2024 08:48:05 -0700
    Tim Rentsch <[email protected]> wrote:

    bart <[email protected]> writes:

    I earlier asked this:

    "So if arrays aren't passed by value in C, and they aren't passed
    by reference, then how the hell ARE they passed?!"

    They aren't. C allows lots of things to be passed as an argument
    to a function: several varieties of numeric values, structs,
    unions, and pointers, including both pointers to object types and
    pointers to function types. C does not have a way for a function
    to take an argument that is either an array or a function. There
    is a way to take pointers to those things, but not the things
    themselves. Arrays and functions are second-class values in C.


    I'd like to see an example of the language that permits ahead-of-time compilation and has functions as first-class values.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Wed Jul 10 21:39:10 2024
    On Wed, 10 Jul 2024 18:30:54 +0100
    bart <[email protected]> wrote:

    On 10/07/2024 16:48, Tim Rentsch wrote:
    bart <[email protected]> writes:

    I earlier asked this:

    "So if arrays aren't passed by value in C, and they aren't passed
    by reference, then how the hell ARE they passed?!"

    They aren't. C allows lots of things to be passed as an argument
    to a function: several varieties of numeric values, structs,
    unions, and pointers, including both pointers to object types and
    pointers to function types. C does not have a way for a function
    to take an argument that is either an array or a function. There
    is a way to take pointers to those things, but not the things
    themselves. Arrays and functions are second-class values in C.

    That's a good point. It's not just arrays that can't be passed by
    value (because the language says so) but also functions (because its
    not meaningful).

    Yet, although pointers to arrays and function can be passed (without
    even doing anything special like using &), you are not allowed to say
    that anything is passed by reference in C!

    The automatic conversion to a pointer, which is also a feature of
    true pass-by-reference, doesn't count.

    Not needing an explicit deref inside the callee (another
    characteristic of pass-by-reference) doesn't count either.

    It does not count, because automatic conversion to a pointer is not
    something that happens only during parameter passing. For arrays, it
    happens in all contexts except sizeof(). For functions, it happens in
    all contexts except function call. Or, may be, including function call,
    in this case (but not in case of arrays) it depends on point of view.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Michael S on Wed Jul 10 22:49:07 2024
    On 2024-07-10, Michael S <[email protected]> wrote:
    I'd like to see an example of the language that permits ahead-of-time compilation and has functions as first-class values.

    Common Lisp.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @[email protected]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Thu Jul 11 11:13:57 2024
    On Wed, 10 Jul 2024 21:28:15 +0200
    David Brown <[email protected]> wrote:

    On 10/07/2024 19:14, Michael S wrote:
    On Wed, 10 Jul 2024 08:48:05 -0700
    Tim Rentsch <[email protected]> wrote:

    bart <[email protected]> writes:

    I earlier asked this:

    "So if arrays aren't passed by value in C, and they aren't passed
    by reference, then how the hell ARE they passed?!"

    They aren't. C allows lots of things to be passed as an argument
    to a function: several varieties of numeric values, structs,
    unions, and pointers, including both pointers to object types and
    pointers to function types. C does not have a way for a function
    to take an argument that is either an array or a function. There
    is a way to take pointers to those things, but not the things
    themselves. Arrays and functions are second-class values in C.


    I'd like to see an example of the language that permits
    ahead-of-time compilation and has functions as first-class values.


    Haskell is the first the comes to mind for me, but you could pick any compiled functional programming language.

    I am by no means a Haskell expert, and I am not at all familiar with
    the way the language is compiled. But it is quite clear that it is
    an example of a language that has functions as first-class objects,
    and which is ahead-of-time compiled. The example below defines an
    int-to-int function "doubler", and also a function-to-function
    function "doTwice", and a function quadrupler that is defined as the
    result of applying the higher-order function doTwice to doubler.
    These are all compiled to assembly.

    <https://godbolt.org/z/Tb7hGYsdv>


    module Example where

    doubler :: Int -> Int
    doubler x = 2 * x

    doTwice :: (Int -> Int) -> (Int -> Int)
    doTwice f x = f (f x)

    quadrupler = doTwice doubler

    shouldBeEighty = quadrupler 20



    You can write much the same in C++ using lambdas (which are objects
    and can be passed around and returned as such) and templates (which
    are needed because the type of lambdas is hidden). Unfortunately,
    this also means that the functions don't get individually generated
    functions in assembly:

    <https://godbolt.org/z/KvPWz3n8z>

    auto doubler = [](int x) -> int { return 2 * x; };

    auto doTwice = [](auto f) -> auto
    {
    return [f](int x) -> int { return f(f(x)); };
    };

    auto quadrupler = doTwice(doubler);

    auto shouldBeEiqhty = quadrupler(20);


    I fail to see a material difference between first class function values
    in Haskell and C++ and first class function pointer values in C:

    int doubler(int x) {
    return x*2;
    }
    int doTwice(int (*foo)(int), int x) {
    return foo(foo(x));
    }
    int quadrupler(int x) {
    return doTwice(doubler, x);
    }

    I am willing to believe that the difference exists, but your example is
    too basic to demonstrate it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Thu Jul 11 11:31:32 2024
    On Wed, 10 Jul 2024 20:04:35 +0100
    bart <[email protected]> wrote:

    On 10/07/2024 19:39, Michael S wrote:
    On Wed, 10 Jul 2024 18:30:54 +0100
    bart <[email protected]> wrote:

    On 10/07/2024 16:48, Tim Rentsch wrote:
    bart <[email protected]> writes:

    I earlier asked this:

    "So if arrays aren't passed by value in C, and they aren't passed
    by reference, then how the hell ARE they passed?!"

    They aren't. C allows lots of things to be passed as an argument
    to a function: several varieties of numeric values, structs,
    unions, and pointers, including both pointers to object types and
    pointers to function types. C does not have a way for a function
    to take an argument that is either an array or a function. There
    is a way to take pointers to those things, but not the things
    themselves. Arrays and functions are second-class values in C.

    That's a good point. It's not just arrays that can't be passed by
    value (because the language says so) but also functions (because
    its not meaningful).

    Yet, although pointers to arrays and function can be passed
    (without even doing anything special like using &), you are not
    allowed to say that anything is passed by reference in C!

    The automatic conversion to a pointer, which is also a feature of
    true pass-by-reference, doesn't count.

    Not needing an explicit deref inside the callee (another
    characteristic of pass-by-reference) doesn't count either.

    It does not count, because automatic conversion to a pointer is not something that happens only during parameter passing. For arrays, it happens in all contexts except sizeof(). For functions, it happens
    in all contexts except function call. Or, may be, including
    function call, in this case (but not in case of arrays) it depends
    on point of view.

    Suppose that was to happen in all contexts, not just for arrays and functions, but for all types.

    That means that if A, B, C were numbers, then any call such as F(A,
    B, C) would pass the addresses of the numbers rather than their
    values.

    According to what people have said, C would STILL be a language that
    passed thing by value, and never by automatic reference.

    Yet in my scenario that now sounds ludicrous.


    No, if dereference operator would be required consistently in nearly
    all contexts then it would not be ludicrous at all.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Thu Jul 11 11:54:18 2024
    On Thu, 11 Jul 2024 01:21:52 +0100
    bart <[email protected]> wrote:

    On 11/07/2024 00:01, Ben Bacarisse wrote:
    bart <[email protected]> writes:

    On 10/07/2024 14:32, Ben Bacarisse wrote:

    I still consider arrays in C to be 'passed' by a
    mechanism which is near-indistinguishable from actual
    pass-by-reference.

    I don't really care how you consider it, but I do care about how you misrepresent the facts in public.

    In another post you said that your language has pass by reference,
    and we also know you have implemented C. Either you are just very
    confused and your language simply has call by value (after all, you
    think C has pass by reference), or you know that pass by reference
    in your language needs something from the implementation that was
    not needed when you implemented C. I can't decide if you are
    confused or just lying.


    The way it works in my language is very simple (this is what I do
    after all):

    type T = int

    proc F(T x)= # Pass by value
    println x.typestr
    end

    proc G(ref T x)= # Manual pass-by-reference
    println x^.typestr
    end

    proc H(T &x)= # Auto pass-by-reference
    println x.typestr
    end

    proc main=
    T a

    F(a)
    G(&a)
    H(a)
    end

    I've written 3 functions using pass-by-value, pass-by-value emulating pass-by-reference, and actual pass-by-reference.

    The G function and the call to G show what the compiler has to add
    when it processes function H: address-of ops and derefs. The cost is
    a single & in the parameter list to get that convenience.

    This programs works just the same if T was changed to an array:

    type T = [4]int

    (The output is 3 lots of '[4]i64' instead of 3 lots of 'i64'; 'int'
    is an alias for int64/i64.)

    This is regular and orthogonal, a complete contrast to C even though
    both languages supposedly operate at the same level.

    The behaviour of F, when written in C, is like my F function when T
    is an int (obviously the C won't have '.typestr').

    But when T is an array, its behaviour is more like that of my H
    function.

    So, my remark about arrays in C being passed by reference is
    understandable.


    No, it isn't.
    If [in C] it was possible to pass arrays to functions, either by value
    or by reference, then callee would know the length of passed array. As
    it is, callee does not know it.
    The length can be passed in a separate parameter, but then it does not
    have to be the same as an original.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Michael S on Thu Jul 11 08:41:14 2024
    On 2024-07-11, Michael S <[email protected]> wrote:
    On Wed, 10 Jul 2024 21:28:15 +0200
    David Brown <[email protected]> wrote:

    On 10/07/2024 19:14, Michael S wrote:
    On Wed, 10 Jul 2024 08:48:05 -0700
    Tim Rentsch <[email protected]> wrote:

    bart <[email protected]> writes:

    I earlier asked this:

    "So if arrays aren't passed by value in C, and they aren't passed
    by reference, then how the hell ARE they passed?!"

    They aren't. C allows lots of things to be passed as an argument
    to a function: several varieties of numeric values, structs,
    unions, and pointers, including both pointers to object types and
    pointers to function types. C does not have a way for a function
    to take an argument that is either an array or a function. There
    is a way to take pointers to those things, but not the things
    themselves. Arrays and functions are second-class values in C.


    I'd like to see an example of the language that permits
    ahead-of-time compilation and has functions as first-class values.


    Haskell is the first the comes to mind for me, but you could pick any
    compiled functional programming language.

    I am by no means a Haskell expert, and I am not at all familiar with
    the way the language is compiled. But it is quite clear that it is
    an example of a language that has functions as first-class objects,
    and which is ahead-of-time compiled. The example below defines an
    int-to-int function "doubler", and also a function-to-function
    function "doTwice", and a function quadrupler that is defined as the
    result of applying the higher-order function doTwice to doubler.
    These are all compiled to assembly.

    <https://godbolt.org/z/Tb7hGYsdv>


    module Example where

    doubler :: Int -> Int
    doubler x = 2 * x

    doTwice :: (Int -> Int) -> (Int -> Int)
    doTwice f x = f (f x)

    quadrupler = doTwice doubler

    shouldBeEighty = quadrupler 20



    You can write much the same in C++ using lambdas (which are objects
    and can be passed around and returned as such) and templates (which
    are needed because the type of lambdas is hidden). Unfortunately,
    this also means that the functions don't get individually generated
    functions in assembly:

    <https://godbolt.org/z/KvPWz3n8z>

    auto doubler = [](int x) -> int { return 2 * x; };

    auto doTwice = [](auto f) -> auto
    {
    return [f](int x) -> int { return f(f(x)); };
    };

    auto quadrupler = doTwice(doubler);

    auto shouldBeEiqhty = quadrupler(20);


    I fail to see a material difference between first class function values
    in Haskell and C++ and first class function pointer values in C:

    int doubler(int x) {
    return x*2;
    }
    int doTwice(int (*foo)(int), int x) {
    return foo(foo(x));
    }
    int quadrupler(int x) {
    return doTwice(doubler, x);
    }

    I am willing to believe that the difference exists, but your example is
    too basic to demonstrate it.

    First class functions could do something like this:

    // multiplier takes a coefficient and returns a pointer to
    // function

    int (*multiplier(int coefficient))(int) {
    // fantasy lambda syntax. Return type int is written after
    // parameter list.
    return lambda(int x) int {
    return coefficient * x;
    }
    }

    int (*doubler)(int) = multiplier(2);

    int x = doubler(42); // x becomes 84

    Even though the lambda is returned out of multiplier, whose execution terminates, when the returned function is invoked, it can refer to the coefficient, which is captured in a lexical closure.

    With a C-like typedef, we can declutter the definition of mutiplier:

    typedef int (*int_int_fn)(int);

    int_int_fn multiplier(int coefficient) {
    return lambda(int x) int {
    return coefficient * x;
    }
    }

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @[email protected]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Kaz Kylheku on Thu Jul 11 12:15:02 2024
    On Thu, 11 Jul 2024 08:41:14 -0000 (UTC)
    Kaz Kylheku <[email protected]> wrote:

    On 2024-07-11, Michael S <[email protected]> wrote:
    On Wed, 10 Jul 2024 21:28:15 +0200
    David Brown <[email protected]> wrote:

    On 10/07/2024 19:14, Michael S wrote:
    On Wed, 10 Jul 2024 08:48:05 -0700
    Tim Rentsch <[email protected]> wrote:

    bart <[email protected]> writes:

    I earlier asked this:

    "So if arrays aren't passed by value in C, and they aren't
    passed by reference, then how the hell ARE they passed?!"

    They aren't. C allows lots of things to be passed as an
    argument to a function: several varieties of numeric values,
    structs, unions, and pointers, including both pointers to
    object types and pointers to function types. C does not have a
    way for a function to take an argument that is either an array
    or a function. There is a way to take pointers to those
    things, but not the things themselves. Arrays and functions
    are second-class values in C.

    I'd like to see an example of the language that permits
    ahead-of-time compilation and has functions as first-class
    values.

    Haskell is the first the comes to mind for me, but you could pick
    any compiled functional programming language.

    I am by no means a Haskell expert, and I am not at all familiar
    with the way the language is compiled. But it is quite clear that
    it is an example of a language that has functions as first-class
    objects, and which is ahead-of-time compiled. The example below
    defines an int-to-int function "doubler", and also a
    function-to-function function "doTwice", and a function quadrupler
    that is defined as the result of applying the higher-order
    function doTwice to doubler. These are all compiled to assembly.

    <https://godbolt.org/z/Tb7hGYsdv>


    module Example where

    doubler :: Int -> Int
    doubler x = 2 * x

    doTwice :: (Int -> Int) -> (Int -> Int)
    doTwice f x = f (f x)

    quadrupler = doTwice doubler

    shouldBeEighty = quadrupler 20



    You can write much the same in C++ using lambdas (which are objects
    and can be passed around and returned as such) and templates (which
    are needed because the type of lambdas is hidden). Unfortunately,
    this also means that the functions don't get individually generated
    functions in assembly:

    <https://godbolt.org/z/KvPWz3n8z>

    auto doubler = [](int x) -> int { return 2 * x; };

    auto doTwice = [](auto f) -> auto
    {
    return [f](int x) -> int { return f(f(x)); };
    };

    auto quadrupler = doTwice(doubler);

    auto shouldBeEiqhty = quadrupler(20);


    I fail to see a material difference between first class function
    values in Haskell and C++ and first class function pointer values
    in C:

    int doubler(int x) {
    return x*2;
    }
    int doTwice(int (*foo)(int), int x) {
    return foo(foo(x));
    }
    int quadrupler(int x) {
    return doTwice(doubler, x);
    }

    I am willing to believe that the difference exists, but your
    example is too basic to demonstrate it.

    First class functions could do something like this:

    // multiplier takes a coefficient and returns a pointer to
    // function

    int (*multiplier(int coefficient))(int) {
    // fantasy lambda syntax. Return type int is written after
    // parameter list.
    return lambda(int x) int {
    return coefficient * x;
    }
    }

    int (*doubler)(int) = multiplier(2);

    int x = doubler(42); // x becomes 84

    Even though the lambda is returned out of multiplier, whose execution terminates, when the returned function is invoked, it can refer to the coefficient, which is captured in a lexical closure.

    With a C-like typedef, we can declutter the definition of mutiplier:

    typedef int (*int_int_fn)(int);

    int_int_fn multiplier(int coefficient) {
    return lambda(int x) int {
    return coefficient * x;
    }
    }


    Thank you.
    Your example confirms my suspicion that the difference between first
    and second class of functions doesn't become material until language
    supports closures.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Michael S on Thu Jul 11 10:02:04 2024
    On 2024-07-11, Michael S <[email protected]> wrote:

    With a C-like typedef, we can declutter the definition of mutiplier:

    typedef int (*int_int_fn)(int);

    int_int_fn multiplier(int coefficient) {
    return lambda(int x) int {
    return coefficient * x;
    }
    }


    Thank you.
    Your example confirms my suspicion that the difference between first
    and second class of functions doesn't become material until language
    supports closures.

    It sort of becomes half-material when the language supports downward-funarg-only closures, like Pascal and GNU C,
    where our lambda is good as long as multiplier doesn't exit.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @[email protected]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to bart on Thu Jul 11 13:25:19 2024
    On Thu, 11 Jul 2024 11:04:13 +0100
    bart <[email protected]> wrote:

    On 11/07/2024 09:54, Michael S wrote:
    On Thu, 11 Jul 2024 01:21:52 +0100
    bart <[email protected]> wrote:

    On 11/07/2024 00:01, Ben Bacarisse wrote:
    bart <[email protected]> writes:

    On 10/07/2024 14:32, Ben Bacarisse wrote:

    I still consider arrays in C to be 'passed' by a
    mechanism which is near-indistinguishable from actual
    pass-by-reference.

    I don't really care how you consider it, but I do care about how
    you misrepresent the facts in public.

    In another post you said that your language has pass by reference,
    and we also know you have implemented C. Either you are just very
    confused and your language simply has call by value (after all,
    you think C has pass by reference), or you know that pass by
    reference in your language needs something from the
    implementation that was not needed when you implemented C. I
    can't decide if you are confused or just lying.


    The way it works in my language is very simple (this is what I do
    after all):

    type T = int

    proc F(T x)= # Pass by value
    println x.typestr
    end

    proc G(ref T x)= # Manual pass-by-reference
    println x^.typestr
    end

    proc H(T &x)= # Auto pass-by-reference
    println x.typestr
    end

    proc main=
    T a

    F(a)
    G(&a)
    H(a)
    end

    I've written 3 functions using pass-by-value, pass-by-value
    emulating pass-by-reference, and actual pass-by-reference.

    The G function and the call to G show what the compiler has to add
    when it processes function H: address-of ops and derefs. The cost
    is a single & in the parameter list to get that convenience.

    This programs works just the same if T was changed to an array:

    type T = [4]int

    (The output is 3 lots of '[4]i64' instead of 3 lots of 'i64'; 'int'
    is an alias for int64/i64.)

    This is regular and orthogonal, a complete contrast to C even
    though both languages supposedly operate at the same level.

    The behaviour of F, when written in C, is like my F function when T
    is an int (obviously the C won't have '.typestr').

    But when T is an array, its behaviour is more like that of my H
    function.

    So, my remark about arrays in C being passed by reference is
    understandable.


    No, it isn't.
    If [in C] it was possible to pass arrays to functions, either by
    value or by reference, then callee would know the length of passed
    array. As it is, callee does not know it.

    The length can be passed in a separate parameter, but then it does
    not have to be the same as an original.

    That's rather specious. In my language (probably in C too), most
    passed arrays are unbounded, allowing the same function to work with
    arrays of different sizes.

    So that would need a separate Length parameter, even using
    by-reference.

    In that regard, it's no different from the C: my array by-ref and C's alledged by-ref both cannot determine the array length solely from
    the parameter.

    (In my language, attempts to get the length yields 0, which makes
    sense as the parameter's bounds are zero. In C, it will yield the
    size of the pointer.)

    But when the array IS bounded, then in C:

    typedef byte vector[4];

    void F(vector a) {
    printf("%zu\n", sizeof(a));
    printf("%zu\n", sizeof(vector));
    }

    The first printf shows 8 (the pointer size); the second shows 4 (the
    array size). So it /can/ access the bounds.


    It can access the bounds of type vector. But parameter a is not of type
    vector despite the declaration.
    And yes, I think that C would have been better language if the code as
    above was a syntax error. But this battle was lost when I was in the
    middle school.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Janis Papanagnou on Fri Jul 12 11:52:25 2024
    On 2024-07-12, Janis Papanagnou <[email protected]> wrote:
    On 12.07.2024 08:00, David Brown wrote:
    [...]

    I can understand when someone new to C gets mixed up about how arrays
    work.

    I can't understand that if I presume that the person has read any
    basic textbook about "C".

    Problem is that over the years there have been authors of basic textbooks about "C" who were also confused by things like this.

    For instance, in Herbert Schildt's "C: The Complete Reference",
    3rd Ed, page 53, this can be found:

    /* Write 6 integers to a disk file. */
    void put_rec(int rec[6], FILE *fp)
    {
    int len;

    len = fwrite(rec, sizeof rec, 1, fp);
    if(len != 1) printf("write error");
    }

    Of course, "sizeof rec" is the size of a pointer, not likely
    equal to the size of an array of 6 elements.

    The intersection of authors who are skillful presenters of material, knowledgeable about C, and motivated to write about it has not been that large. We could add to that, "write about new C, and motivated to keep up with ISO C developments and crank out new edititons".




    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @[email protected]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to bart on Fri Jul 12 12:14:40 2024
    On 2024-07-12, bart <[email protected]> wrote:
    It's clearly not by value. It's apparently not by reference. You can't
    get away with saying they are not passed, as clearly functions *can*
    access array data via parameters.

    Actually, you probably can get away with saying that it is "passed
    by reference".

    The formal term that doesn't apply is "call by reference"; that's what
    C doesn't have.

    "call by reference" emphasizes that the function call mechanism
    provides the reference semantics for a formal parameter, not that some arbitrary means of passage of the data has reference semantics.

    The following also achieves "pass by reference":

    int *global;

    void child(void)
    {
    printf("%d\", global[13]);
    }

    void parent(void)
    {
    int array[20];
    global = array;
    child();
    }

    "pass" does not mean as a formal parameter.

    For instance "message passing" (e.g. from one thread to
    another) doesn't use formal parameters.

    ISO C uses the "refer" word and derivatives thereof in connection
    with pointers:

    - "If an attempt is made to refer to an object defined with a
    volatile-qualified type through use of an lvalue with
    non-volatile-qualified type, the behavior is undefined".

    The type from which a pointer is derived is called the "referenced
    type":

    - "The construction of a pointer type from a referenced type is
    called ‘‘pointer type derivation’’ [C99]

    A footnote in C99 used the word "dereferencing" to describe the
    action of the unary * operator. This word is commonly used in
    the C programming circles:

    - "Among the invalid values for dereferencing a pointer by the
    unary * operator are a null pointer, ..."

    Another footnote in C99 uses "referenced" describing the relationship
    of an pointer to the target object:

    - "In other words, E depends on the value of P itself rather than
    on the value of an object referenced indirectly through P.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @[email protected]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Kaz Kylheku on Fri Jul 12 15:35:42 2024
    On Fri, 12 Jul 2024 11:52:25 -0000 (UTC)
    Kaz Kylheku <[email protected]> wrote:

    On 2024-07-12, Janis Papanagnou <[email protected]>
    wrote:
    On 12.07.2024 08:00, David Brown wrote:
    [...]

    I can understand when someone new to C gets mixed up about how
    arrays work.

    I can't understand that if I presume that the person has read any
    basic textbook about "C".

    Problem is that over the years there have been authors of basic
    textbooks about "C" who were also confused by things like this.

    For instance, in Herbert Schildt's "C: The Complete Reference",
    3rd Ed, page 53, this can be found:

    /* Write 6 integers to a disk file. */
    void put_rec(int rec[6], FILE *fp)
    {
    int len;

    len = fwrite(rec, sizeof rec, 1, fp);
    if(len != 1) printf("write error");
    }

    Of course, "sizeof rec" is the size of a pointer, not likely
    equal to the size of an array of 6 elements.

    The intersection of authors who are skillful presenters of material, knowledgeable about C, and motivated to write about it has not been
    that large. We could add to that, "write about new C, and motivated
    to keep up with ISO C developments and crank out new edititons".





    I did notread any of his books, by Wiikipedia article says that his
    ability to fill books with mistakes is not lmited to books about C
    language.
    Luckily for readers, it seems that Herbert Schildt left book-wrting
    racket two decades ago.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Janis Papanagnou on Fri Jul 12 16:31:36 2024
    On Fri, 12 Jul 2024 15:07:53 +0200
    Janis Papanagnou <[email protected]> wrote:

    On 12.07.2024 14:42, Michael S wrote:

    I don't share your optimistic belief that the term "pass by
    reference" is really established. Very few terms in computer
    science (science? really?) are established firmly. Except, may be,
    in more theoretical branches of it.

    I don't know of any "standard" describing that - if that's what you
    are aiming at - but I also wouldn't expect an international standard document. And newer sources (specifically including blogs and bots!) certainly may muddy waters.


    I would expect that thousands of occurrences of phrase "passed by
    reference" in relationship with passing explicit pointer to object can
    be found in old books, including books not authorized by Herbert
    Schildt.

    All my sources since days in University had a consistent semantical description.

    Computer Scientists seems not to have been keen to introduce here
    own and different terms.


    They are.

    In case you have other, new [to me], or own concrete semantical interpretations of the "call-by-reference" mechanism I'm certainly
    interested to hear about.

    Especially in the light of alternative facts and "own definitions"
    (like Bart's) I suggest otherwise to not spread FUD about that.
    The gridlocked discussion is already annoying enough. :-/

    Janis


    Not sure what gridlocked discussion do you have in mind.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Bart on Wed Jul 17 16:34:57 2024
    On Wed, 17 Jul 2024 12:38:15 +0100
    Bart <[email protected]> wrote:

    On 13/07/2024 10:39, BGB wrote:

    But, as I see it, no real point in arguing this stuff (personally,
    I have better stuff to be doing...).

    We all do. But this group seems to be about arguing about pointless
    stuff and you might come here when you want a respite from proper
    work.

    However (here I assume you've gone back to Quake but that other
    interested parties might be reading this), consider the program below.

    That sets up an array and then sums its elements by calling 3
    different functions to do the job:

    (1) Using normal C pass-by-value

    (2) Using C pass-by-value to emulate call-by-reference

    (3) Using fantasy true call-by-reference as it might appear if C had
    the feature

    (I'd hoped C++ would run this, but it didn't even like the middle
    function.)

    I'm asking people to compare the first and third functions and their
    calls, and to see if there's any appreciable difference between them.
    There will obviously be a difference in how the A parameter is
    declared.

    ---------------------------------------------
    #include <stdio.h>

    typedef int T;

    int sum_byvalue(T* A, int n) {
    int i, sum=0;
    for (i=0; i<n; ++i) sum += A[i];
    return sum;
    }

    int sum_bymanualref(T(*A)[], int n) {
    int i, sum=0;
    for (i=0; i<n; ++i) sum += (*A)[i];
    return sum;
    }

    int sum_bytrueref(T (&A)[], int n) {
    int i, sum=0;
    for (i=0; i<n; ++i) sum += A[i];
    return sum;
    }

    int main(void) {
    enum {N = 10};
    T A[N] = {10,20,30,40,50,60,70,80,90,100};
    int total=0;

    total += sum_byvalue (A, N);
    total += sum_bymanualref (&A, N);
    total += sum_bytrueref (A, N);

    printf("%d\n", total); // would show 1650
    }
    ---------------------------------------------

    Find anything? I thought not.

    Those findings might suggest that C doesn't need call-by-reference,
    not for arrays anyway. Except that at present you can do this:

    T x=42;
    sum_byvalue(&x, N);

    which would not be possible with call-by-reference. Nor with
    sum_bymanualref, but apparently nobody wants to be doing with all
    that extra, fiddly syntax. Better to be unsafe!

    The C++ syntax your are looking for is sum_bytrueref(std::array<T,10>&A,
    And indeed, the generated code is the same.
    https://godbolt.org/z/dYGoWsdjE
    But why is it the same? Because in C++ arrays are also 2nd class
    citizen, like in C ! std::array is not a 'native' C++ type, but a
    wrapper around array-within-struct pattern.
    The proper comparison would be vs language that has arrays as 1st class citizen.

    I tried to produce Ada example on Godbolt, but it seems that support
    for Ada on GB is too limited. I was not able to convince it to compile
    package. And without packages I was not able to illustrate my point.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Bart on Thu Aug 15 23:29:32 2024
    On 2024-08-15, Bart <[email protected]> wrote:
    On 15/08/2024 22:36, Tim Rentsch wrote:
    I see. So your point is, if we ignore all the ways that the two
    modes are different then they are exactly the same.

    Brilliant deduction, Dr. Watson.

    So your approach is to totally ignore all the ways that the two modes
    are identical.

    Almost any two different things have some attributes that are identical.
    If we consider a bicycle and a fish, we can probably come up with common attributes.

    Passing pointers by value similar to call-by-reference, but also
    different.

    The program can calculate a bad pointer and pass that by value.

    Call-by-reference implementations can take measures to ensure that
    a a bad reference is not passed.

    The function call syntax itself, for a by-reference parameter, requires
    an expression that designates an object, and takes a reference to that
    object implicitly. Inside the function, there is no visible pointer;
    the by-reference argument appears to be an alias for the referenced
    object. Since there is no pointer, the address cannot be incremented
    or reassigned.

    (In a language that has both pointers and call-by-reference, it may
    be possible to calculate a bad pointer, dereference it and use the
    resulting expression as a reference argument. Then the reference
    will be bad: but the root cause is pointer misuse, not the
    call-by-reference mechanism.)

    It is mainly syntactic differences. Call-by-reference can be implemented
    using pointers, which can happen in a very early compiler pass; the
    first intermediate code can already be transformed to using pointers.

    If your point of view is that pointers are what is "real under the
    hood", then call-by-reference is just "syntactic sugar" for pointers.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @[email protected]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Ben Bacarisse on Fri Aug 16 12:10:15 2024
    On Fri, 16 Aug 2024 01:08:15 +0100
    Ben Bacarisse <[email protected]> wrote:

    Bart <[email protected]> writes:

    On 15/08/2024 15:33, Ben Bacarisse wrote:
    Bart <[email protected]> writes:

    On 15/08/2024 09:43, Tim Rentsch wrote:
    Bart <[email protected]> writes:

    C call-by-value
    call-by-reference =============== =================
    at call:

    (array argument) F(A) H(A)

    (pointer argument) F(p) (disallowed)

    My posts were about passing *arrays* and the fact that C's
    pass-by-value was remarkably similar to pass-by-reference.
    Which is why, presumably, you didn't show the differences. Your
    post was all polemic not part of a collegiate discussion of the
    similarities and differences.

    However your entry for pointers is not correct:
    No, the entry is correct. H(p) would be (is?) disallowed when H's
    parameter is a reference to an array.

    Sorry, what language does the right-hand column pertain to? /Any/
    language that has call-by-reference, or Tim's hypthetical language?


    Tim said that case was "disallowed". You call that an error on his
    part. What language did you have in mind that permits such a gross
    warping of types? I would describe /any/ language that allowed it as
    having a design error.

    Or any that could be used to prove him right?

    In general there is no reason, in a language with true
    call-by-reference, why any parameter type T (which has the form U*,
    a pointer to anything), cannot be passed by reference. It doesn't
    matter whether U is an array type or not.

    I can't unravel this. Take, as a concrete example, C++. You can't
    pass a pointer to function that takes an array passed by reference.
    You can, of course, pass a pointer by reference, but that is neither
    here nor there.



    IMHO, C++ is a particularly bad example.
    Yes, C++ has call-by-reference misfeature. But arrays in C++ are
    2nd class citizen, same as in C. They can't be assigned and can't be
    passed to callee, neither by value nor by reference.

    Also, I suspect that if you ask Ken Thompson, he will tell you that C++
    does not really have 'call by reference'. Instead, it has references as
    1st class object, so, naturally, values of references can be used
    during 'call by value'.
    I have enough of respect to KT to consider that his POV is not a
    nonsense.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to Keith Thompson on Fri Aug 16 12:38:10 2024
    On Fri, 16 Aug 2024 02:18:15 -0700
    Keith Thompson <[email protected]> wrote:

    Michael S <[email protected]> writes:
    [...]
    IMHO, C++ is a particularly bad example.
    Yes, C++ has call-by-reference misfeature. But arrays in C++ are
    2nd class citizen, same as in C. They can't be assigned and can't be
    passed to callee, neither by value nor by reference.

    Also, I suspect that if you ask Ken Thompson, he will tell you that
    C++ does not really have 'call by reference'. Instead, it has
    references as 1st class object, so, naturally, values of references
    can be used during 'call by value'.
    I have enough of respect to KT to consider that his POV is not a
    nonsense.

    Is that an attempt at proof by authority?

    Yes!

    Not only does Ken Thompson
    have very little to do with C++, but you're basing your conclusion on
    what you *suspect* he would say.


    Yes, but it's not baseless.
    It is based on following section Go language FAQs that I assumed to be
    either authored or approved by KT.
    https://go.dev/doc/faq#pass_by_value

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael S@21:1/5 to David Brown on Mon Aug 19 12:22:08 2024
    On Mon, 19 Aug 2024 09:26:46 +0200
    David Brown <[email protected]> wrote:

    On 19/08/2024 03:03, Tim Rentsch wrote:
    Ben Bacarisse <[email protected]> writes:

    David Brown <[email protected]> writes:

    On 16/08/2024 12:00, Ben Bacarisse wrote:

    David Brown <[email protected]> writes:

    On 16/08/2024 02:08, Ben Bacarisse wrote:

    Bart <[email protected]> writes:

    In general there is no reason, in a language with true
    call-by-reference, why any parameter type T (which has the
    form U*, a pointer to anything), cannot be passed by
    reference. It doesn't matter whether U is an array type or
    not.

    I can't unravel this. Take, as a concrete example, C++. You
    can't pass a pointer to function that takes an array passed by
    reference. You can, of course, pass a pointer by reference,
    but that is neither here nor there.

    In C++, you can't pass arrays as parameters at all - the
    language inherited C's handling of arrays. You can, of course,
    pass objects of std::array<> type by value or by reference,
    just like any other class types.

    The best way to think about C++ (in my very non-expert opinion)
    is to consider references as values that are passed by, err...,
    value. But you seem prepared to accept that some things can be
    "passed by reference" in C++.

    That seems a subtle distinction - I'll have to think about it a
    little. I like your description of arguments being like local
    variable initialisation - it makes sense equally well regardless
    of whether the parameter is "int", "int*", or "int&". (It's
    probably best not to mention the other one in this group...)

    So if this:
    #include <iostream>
    void g(int &i) { std::cout << i << "\n"; }
    int main(void)
    {
    int I{0};
    g(I);
    }
    shows an int object, I, being passed to g, why does this
    #include <iostream>
    void f(int (&ar)[10]) { std::cout << sizeof ar << "\n"; }
    int main(void)
    {
    int A[10];
    f(A);
    }
    not show an array, A, being passed to f?

    That's backwards compatibility with C array handling at play.

    I'm not sure how this answers my question. Maybe you weren't
    answering it and were just making a remark...

    My guess is he didn't understand the question. The code shown
    has nothing to do with backwards compatibility with C array
    handling.

    I had intended to make a brief remark and thought that was all that
    was needed to answer the question. But having thought about it a bit
    more (prompted by these last two posts), and tested the code (on the assumption that the gcc writers know the details better than I do),
    you are correct - I did misunderstand the question. I was wrong in
    how I thought array reference parameters worked in C++, and the way
    Ben worded the question re-enforced that misunderstanding.

    I interpreted his question as saying that the code "f" does not show
    an array type being passed by reference, with the implication that
    the "sizeof" showed the size of a pointer, not the size of an array
    of 10 ints, and asking why C++ was defined that way. The answer, as
    I saw it, was that C++ made reference parameters to arrays work much
    like pointer parameters to arrays, and those work like in C for
    backwards compatibility.

    Of course, it turns out I was completely wrong about how array type
    reference parameters work in C++. It's not something I have had use
    for in my own C++ programming or something I have come across in
    other code that I can remember, and I had made incorrect assumptions
    about it. Now that I corrected that, it all makes a lot more sense.

    And so I presume Ben was actually asking why I /thought/ this was not
    passing an array type (thus with its full type information, including
    its size). Then answer there is now obvious - I thought that because
    I had jumped to incorrect conclusions about array reference
    parameters in C++.

    So thank you (Ben and Tim) for pushing me to correct my C++
    misunderstanding here, and apologies to anyone confused by my mistake.



    In this particular case C++ behaves very similarly to non-extended
    Pascal as described in "PASCAL User Manual and Report".
    It treats size of array as part of the type.

    I am not sure that description of observed compiler's behavior as
    "passing an array type with its full type information, including
    its size" is a correct one. Or, may be, it is formally correct, but not enlightening. IMHO, the better description is that
    compiler does strict type checks at caller site that among other things include checks of the size of the array.

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