• on call by reference

    From Johanne Fairchild@21:1/5 to All on Tue Mar 19 05:55:18 2024
    I tried to answer whether Scheme was call-by-reference and I did not
    think the definition of call-by-reference seen on the web is precise
    enough. For instance,

    Call by reference (or pass by reference) is an evaluation strategy
    where a parameter is bound to an implicit reference to the variable
    used as argument, rather than a copy of its value. This typically
    means that the function can modify (i.e., assign to) the variable used
    as argument—something that will be seen by its caller.

    Source:
    https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_reference

    It doesn't say how the modification is done. So we can say that Python
    is call-by-reference, but surely not whe the data is imutable---then
    Python is sometimes call-by-reference. Just this observation already
    makes a language sometimes call-by-reference and sometimes not. So

    ``Is Scheme call-by-reference?''

    would not make any sense. We can change data by way of its argument---set-car!, say. On the other hand, in Scheme arguments are
    passed with an implicit reference to the variable, so it is
    call-by-reference, except perhaps when the argument is immutable.

    So I am totally confused. These definition seem like a mess.

    Can you point me out to good definitions you might know of in academic
    books on the subject? Thank you.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Johanne Fairchild on Tue Mar 19 22:26:01 2024
    On Tue, 19 Mar 2024 05:55:18 -0300, Johanne Fairchild wrote:

    So we can say that Python is call-by-reference, but surely not whe the
    data is imutable---then Python is sometimes call-by-reference.

    Python is call-by-value. It’s just that the concept of “value” also includes “pointer to object”.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alan Bawden@21:1/5 to All on Tue Mar 19 23:08:35 2024
    Scheme is call-by-value. Python is call-by-value. Java is
    call-by-value. C is call-by-value. In none of those languages can you
    write a procedure that assigns a variable used as an argument to that procedure. Read that carefully. "Assigns" means to change what the
    variable references. "Assigns" does _not_ mean to make modifications to
    the thing that the variable references. In Python terms "x = 4" is an assignment to "x", but "x[1] = 4" is not an assignment to "x" because afterwards "x" still references the same object.

    English is a bit slippery here, so people often find this distinction confusing. To make it clearer ask yourself what it means to "change
    your socks". Does it mean you took your socks off and put on a
    different pair? Or does it mean you dyed the socks you are wearing a
    different color?

    A call by value language doesn't let you put on a different pair of
    socks, it only lets you dye them a different color.

    - Alan

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Dmitri Volkov on Wed Mar 20 03:10:55 2024
    On Tue, 19 Mar 2024 21:28:04 -0400, Dmitri Volkov wrote:

    My understanding that in a call-by-reference language, the variables themselves are passed ...

    This is right.

    Though what happens in a language like Perl, where you can obtain
    references to variables (e.g. “\$a”) as values in their own right?

    I guess this is where you a really blurring the boundaries ...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johanne Fairchild@21:1/5 to Alan Bawden on Wed Mar 20 16:20:53 2024
    Alan Bawden <alan@csail.mit.edu> writes:

    Scheme is call-by-value. Python is call-by-value. Java is
    call-by-value. C is call-by-value. In none of those languages can you
    write a procedure that assigns a variable used as an argument to that procedure. Read that carefully. "Assigns" means to change what the
    variable references. "Assigns" does _not_ mean to make modifications to
    the thing that the variable references. In Python terms "x = 4" is an assignment to "x", but "x[1] = 4" is not an assignment to "x" because afterwards "x" still references the same object.

    Thank you. That's *very* helpful.

    English is a bit slippery here, so people often find this distinction confusing. To make it clearer ask yourself what it means to "change
    your socks". Does it mean you took your socks off and put on a
    different pair? Or does it mean you dyed the socks you are wearing a different color?

    A call by value language doesn't let you put on a different pair of
    socks, it only lets you dye them a different color.

    If I understand it right, call-by-reference means the same variable that
    was outside of a procedure call gets passed in to the procedure. So if
    I assign a new value to it, it /must/ change the value outside because
    it is the /same/ variable. So I would've expected the analogy to
    somehow say that call-by-reference doesn't let me change socks at all.
    It wouldn't even let me dye them a different color. I haven't
    understood the analogy. What gets mapped to the socks-idea? (Not
    variables, I guess.)

    Call-by-value means a procedure gets a copy of the variable that was
    outside of the procedure, although this copy might contain the location
    of some data and so the procedure is able to go to that location and
    make changes to the data.

    Thanks so much!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alan Bawden@21:1/5 to All on Wed Mar 20 18:34:37 2024
    Johanne Fairchild <jfairchild@tudado.org> writes:

    If I understand it right, call-by-reference means the same variable that
    was outside of a procedure call gets passed in to the procedure. So if
    I assign a new value to it, it /must/ change the value outside because
    it is the /same/ variable. So I would've expected the analogy to
    somehow say that call-by-reference doesn't let me change socks at all.

    You would? You must be completely mis-interpreting my analogy because I
    cannot for the life of me figure out how you came to that expectation!
    But don't sweat it -- it's just an analogy. Stick to what I said
    first: "x[1] = 4" does not make "x" refer to a different thing.

    - Alan

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johanne Fairchild@21:1/5 to Alan Bawden on Wed Mar 20 19:50:57 2024
    Alan Bawden <alan@csail.mit.edu> writes:

    Johanne Fairchild <jfairchild@tudado.org> writes:

    If I understand it right, call-by-reference means the same variable that
    was outside of a procedure call gets passed in to the procedure. So if
    I assign a new value to it, it /must/ change the value outside because
    it is the /same/ variable. So I would've expected the analogy to
    somehow say that call-by-reference doesn't let me change socks at all.

    You would? You must be completely mis-interpreting my analogy because I cannot for the life of me figure out how you came to that expectation!
    But don't sweat it -- it's just an analogy. Stick to what I said
    first: "x[1] = 4" does not make "x" refer to a different thing.

    I didn't understand the analogy. (I'm slow!) I have a clue what the misunderstanding is, but let's leave it alone. The example is good and
    I feel I understand the concept now. Thank you so much.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alan Bawden@21:1/5 to Schol-R-LEA on Wed Mar 20 18:22:14 2024
    Schol-R-LEA <alicetrillianosako@gmail.com> writes:

    Johanne Fairchild:
    > I tried to answer whether Scheme was call-by-reference and I did not
    > think the definition of call-by-reference seen on the web is precise
    > enough.

    Scheme is call-by-value; arguments to procedures are copied into the
    parameters in the procedure's environment. As I understand it, even when
    the argument is a reference - such as with a list - a full copy of the
    argument is made local to the procedure.

    If by "a full copy" you mean that a list passed to a procedure will be
    copied, then you are mistaken.

    - Alan

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Schol-R-LEA on Wed Mar 20 23:58:02 2024
    On Wed, 20 Mar 2024 10:57:18 -0400, Schol-R-LEA wrote:

    Languages such as C and C++ are interesting in this regard, as they have
    only call-by-value semantics, but also support passing explicit
    pointers, which allows them to simulate call-by-reference semantics by
    the passing of explicit pointers.

    C++ allows “references”, where the “pointer” part is no longer explicit.
    E.g.

    ResType Func
    (
    ArgType & Arg
    )
    {
    ...
    } /*Func*/

    But of course this is not tied to function arguments at all, and can be
    used elsewhere, e.g.

    int A;
    int & const B = A;

    Now any assignment to “B” actually changes the value of “A”.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Vine@21:1/5 to Schol-R-LEA on Thu Mar 21 18:08:12 2024
    On Wed, 20 Mar 2024 11:07:36 -0400
    Schol-R-LEA <alicetrillianosako@gmail.com> wrote:
    I apologize, I lost my train of thought for part of this:

    Schol-R-LEA:

    In call-by-reference, what is passed is a pointer or similar reference
    to the

    ...to the variable.

    In effect, a language in which call-by-reference is used, parameters are implicit pointers to the arguments. So, by comparison to C,

    void foo(int bar)
    {
    bar = 23;
    }

    in a call-by-reference dialect would be equivalent to

    void foo(int* bar)
    {
    *bar = 23;
    }

    in standard C.

    For obvious reasons, this presents problems with potential side effects
    and is harmful to modularity, as any change to the parameter variable
    would silently change the argument. This is why most languages which
    support call-by-reference at all do so explicitly, with call-by-value
    being the default.

    However that analysis does not help you very much with scheme. Scheme
    is call by value but for mutable entities it behaves like call by
    reference, in that the thing passed by value is analogous to a
    pointer. Scheme is call by value in the sense that all the arguments
    of a procedure must be evaluated before the body of the procedure is
    entered; and any "reseating" of an identifier within a procedure does
    not reseat the reference viewed lexically outside the procedure (see
    below).

    Let's first deal with a preliminary issue. In scheme, set! does not
    mutate any value. Instead it "reseats" an identifier name so that that identifier refers to a different entity than the one it previously
    referred to. The thing previously referred to is unchanged, except
    that if no other identifier refers to it it might be garbage collected
    as unreachable. Take this simple example:

    (let* ([a '(x)]
    [b a]
    [change (lambda (arg) (set! arg 2))])
    (write a)(newline)
    (write b)(newline)
    (change a) ;; outside the change procedure neither a nor b is changed
    (write a)(newline)
    (write b)(newline))

    However entities which may be mutated are as if passed by pointer.
    Here is an example of a list:

    (let* ([a (list `x)]
    [b a]
    [change (lambda (arg) (set-car! arg 'y))])
    (write a)(newline)
    (write b)(newline)
    (change a) ;; changes the list referred to by a and b
    (write a)(newline)
    (write b)(newline))

    And here is an example of a vector:

    (let* ([a (vector 'x 'y)]
    [b a]
    [change (lambda (arg) (vector-set! arg 1 'z))])
    (write a)(newline)
    (write b)(newline)
    (change a) ;; changes the vector referred to by a and b
    (write a)(newline)
    (write b)(newline))

    This is reflected in the way many schemes are implemented. Scalar-like
    things, such as booleans, symbols and integers fitting within 31 or 63
    bits are often "unboxed" or "immediate", that is they are not allocated
    on the garbage collected heap. More complicated things such as lists
    or vectors are usually "boxed". This arrangement is often implemented
    by pointer tagging (https://en.wikipedia.org/wiki/Tagged_pointer).

    Chris

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Chris Vine on Thu Mar 21 21:12:36 2024
    On Thu, 21 Mar 2024 18:08:12 +0000, Chris Vine wrote:

    ... but for mutable entities it behaves like call by reference ...

    This has already been discussed. Only parts of the passed entity can be
    mutated this way, it cannot be replaced with another complete entity as
    far as the caller is concerned. Thus, it is still “call by value”.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Vine@21:1/5 to Lawrence D'Oliveiro on Thu Mar 21 22:02:43 2024
    On Thu, 21 Mar 2024 21:12:36 -0000 (UTC)
    Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
    On Thu, 21 Mar 2024 18:08:12 +0000, Chris Vine wrote:

    ... but for mutable entities it behaves like call by reference ...

    This has already been discussed. Only parts of the passed entity can be mutated this way, it cannot be replaced with another complete entity as
    far as the caller is concerned. Thus, it is still “call by value”.

    Which part of:

    "Scheme is call by value in the sense that ... any 'reseating' of an
    identifier within a procedure does not reseat the reference viewed
    lexically outside the procedure ..."

    were you disagreeing with?

    Chris

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Chris Vine on Fri Mar 22 00:58:38 2024
    On Thu, 21 Mar 2024 22:02:43 +0000, Chris Vine wrote:

    On Thu, 21 Mar 2024 21:12:36 -0000 (UTC) Lawrence D'Oliveiro
    <ldo@nz.invalid> wrote:

    On Thu, 21 Mar 2024 18:08:12 +0000, Chris Vine wrote:

    ... but for mutable entities it behaves like call by reference ...

    This has already been discussed. Only parts of the passed entity can be
    mutated this way, it cannot be replaced with another complete entity as
    far as the caller is concerned. Thus, it is still “call by value”.

    Which part of:

    The part I quoted.

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