• on call by reference

    From Johanne Fairchild@jfairchild@tudado.org to comp.lang.scheme on Tue Mar 19 05:55:18 2024
    From Newsgroup: comp.lang.scheme

    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 argumentrCosomething 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.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Lawrence D'Oliveiro@ldo@nz.invalid to comp.lang.scheme on Tue Mar 19 22:26:01 2024
    From Newsgroup: comp.lang.scheme

    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. ItrCOs just that the concept of rCLvaluerCY also includes rCLpointer to objectrCY.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Dmitri Volkov@dmitri.s.volkov@gmail.com to comp.lang.scheme on Tue Mar 19 21:28:04 2024
    From Newsgroup: comp.lang.scheme

    I believe that scheme is call-by-value. My understanding that in a call-by-reference language, the variables themselves are passed, whereas
    in a call-by-value language, the value of variables are passed.

    Consider the following:

    (define f (lambda (x) (set! x 5) x))
    (define a 3)
    a ; returns 3
    (f a) ; returns 5
    a ; returns 3 for call-by-value, 5 for call-by-reference

    In a call-by-value language, the evaluation order is something like this:

    (f a)
    (f 3)
    ; enter (f 3)
    (set! x 5)
    x
    5 ; return result of (f a)
    a
    3 ; return result of a

    Whereas in a call-by-reference language, the evaluation order is more like:

    (f a)
    ; enter (f a)
    (set! x 5)
    (set! a 5)
    x
    a
    5 ; return result of (f a)
    a
    3 ; return result of a

    It doesn't have to do with whether the types themselves ar immutable or
    not; integers are immutable in pretty much every language.

    This pdf has toy implementations of languages with different calling conventions, which should be useful: https://cgi.luddy.indiana.edu/~c311/lib/exe/fetch.php?media=call-by.pdf

    Anyone please feel free to correct me if anything I put here is wrong.
    Also first time posting on usenet, so if I broke any conventions please
    let me know so that I get them right next time. Thanks!

    On 2024-03-19 4:55 a.-am., Johanne Fairchild wrote:
    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 argumentrCosomething 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.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Alan Bawden@alan@csail.mit.edu to comp.lang.scheme on Tue Mar 19 23:08:35 2024
    From Newsgroup: comp.lang.scheme

    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
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Lawrence D'Oliveiro@ldo@nz.invalid to comp.lang.scheme on Wed Mar 20 03:10:55 2024
    From Newsgroup: comp.lang.scheme

    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. rCL\$arCY) as values in their own right?

    I guess this is where you a really blurring the boundaries ...
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Schol-R-LEA@alicetrillianosako@gmail.com to comp.lang.scheme on Wed Mar 20 10:17:50 2024
    From Newsgroup: comp.lang.scheme

    Dmitri Volkov:> Also first time posting on usenet, so if I broke any conventions please
    let me know so that I get them right next time. Thanks!

    Only in that top posting - that is, putting your reply before the quoted
    text - is generally frowned upon. You usually want to reply below the
    relevant text, such that the answer flows from the question, even if it
    means interleaving multiple answers with different quoted sections.

    All in all, though, not bad for a first post.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Schol-R-LEA@alicetrillianosako@gmail.com to comp.lang.scheme on Wed Mar 20 10:57:18 2024
    From Newsgroup: comp.lang.scheme

    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.

    Each instance where a form alters a value, rather than returning a new
    one, the form is either a primitive form (e.g., (set!), (set-car!), (set-cdr!)) or a macro (in which the body of the macro is expanded into
    the code in place; that is to say, the generated code replaces the macro invocation). The same holds for cases where an argument is conditionally evaluated (e.g., the consequent and alternative in an (if) form).

    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 argumentrCosomething 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.

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

    Very, very few current languages support call-by-reference, and those
    which do generally do so explicitly, such as with Pascal's VAR
    parameters. Even some which allow passing of mutable variables do not
    actually use call-by-reference semantics - Ada, for example, IIUC is
    better described as using call-by-value-and-copy semantics for 'out' and
    'in out' parameters, though the actual implementation may and often does
    use call-by-reference internally, so long as it behaves as if it is
    copying the modified value back to the argument.

    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.

    Similarly, in languages such as Java or Python, call-by-value is used to
    pass variables, whether they hold primitives or object references; but
    since object variables themselves are references (usually, but not necessarily, implemented as pointers) to heap objects, it allows for the referred object to be modified by the referring variables.

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

    Python is always call-by-value; however, in some cases, the 'value' is
    itself a 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.

    As I said earlier, Scheme always uses call-by-value semantics in
    procedures (one could argue that 'classical' Lisp macros use
    call-by-name semantics, whereas hygienic macros use a complex
    combination of call-by-value and call-by-name, but I will leave that to
    others to debate). Only primitive forms and macros can actually modify a value, rather than returning a new one.

    Comments and corrections welcome.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Schol-R-LEA@alicetrillianosako@gmail.com to comp.lang.scheme on Wed Mar 20 11:07:36 2024
    From Newsgroup: comp.lang.scheme

    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.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Johanne Fairchild@jfairchild@tudado.org to comp.lang.scheme on Wed Mar 20 16:20:53 2024
    From Newsgroup: comp.lang.scheme

    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!
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Alan Bawden@alan@csail.mit.edu to comp.lang.scheme on Wed Mar 20 18:22:14 2024
    From Newsgroup: comp.lang.scheme

    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
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Alan Bawden@alan@csail.mit.edu to comp.lang.scheme on Wed Mar 20 18:34:37 2024
    From Newsgroup: comp.lang.scheme

    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
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Johanne Fairchild@jfairchild@tudado.org to comp.lang.scheme on Wed Mar 20 19:50:57 2024
    From Newsgroup: comp.lang.scheme

    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.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Lawrence D'Oliveiro@ldo@nz.invalid to comp.lang.scheme on Wed Mar 20 23:58:02 2024
    From Newsgroup: comp.lang.scheme

    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 rCLreferencesrCY, where the rCLpointerrCY 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 rCLBrCY actually changes the value of rCLArCY.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Schol-R-LEA@alicetrillianosako@gmail.com to comp.lang.scheme on Wed Mar 20 20:59:00 2024
    From Newsgroup: comp.lang.scheme

    Alan Bawden:
    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.

    Ah, thank you for the correction.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Schol-R-LEA@alicetrillianosako@gmail.com to comp.lang.scheme on Wed Mar 20 21:00:20 2024
    From Newsgroup: comp.lang.scheme

    Lawrence D'Oliveiro:
    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 rCLreferencesrCY, where the rCLpointerrCY 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 rCLBrCY actually changes the value of rCLArCY.


    I had forgotten about C++ opaque references. Thank you for pointing that
    out.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Chris Vine@chris@cvine--nospam--.freeserve.co.uk to comp.lang.scheme on Thu Mar 21 18:08:12 2024
    From Newsgroup: comp.lang.scheme

    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
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Lawrence D'Oliveiro@ldo@nz.invalid to comp.lang.scheme on Thu Mar 21 21:12:36 2024
    From Newsgroup: comp.lang.scheme

    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 rCLcall by valuerCY.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Chris Vine@chris@cvine--nospam--.freeserve.co.uk to comp.lang.scheme on Thu Mar 21 22:02:43 2024
    From Newsgroup: comp.lang.scheme

    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 rCLcall by valuerCY.

    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
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Lawrence D'Oliveiro@ldo@nz.invalid to comp.lang.scheme on Fri Mar 22 00:58:38 2024
    From Newsgroup: comp.lang.scheme

    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 rCLcall by valuerCY.

    Which part of:

    The part I quoted.
    --- Synchronet 3.22a-Linux NewsLink 1.2