pointers in Monkey C - bug or by design?

this code

function f(arr)
    {
        arr[0]=11;
        arr[1]=12;
        arr[2]=13;
    }

    function test()
    {
        var x = [1,2,3];
        SYS.println(x);
        f(x);
        SYS.println(x);

    }

produces in console:
[1, 2, 3]
[11, 12, 13]

It means that f  modified external var x. Is it by design or bug?

sdk 4.1b, 4.0.6, 4.0.5...
eclipse CIQ plug in: 4.1.0.beta1
eclipse ver: 2021-09 (4.21.0) Build id: 20210910-1417
windows 10
minSdkVersion 2.4.0
java jre1.8.0_311

  • TL;DR I would prefer to call l in this example an lvalue. (See below).

    "lvalue" is C jargon. Anyway, it just indicates something can be assigned-to (be on the left side of an = (assignment operator). It doesn't clarify reference/value.

    int a = 42;
    int& b = a; // b is now an alias for a

    Actually, the value of b is the (sort-of) "alias". "Alias" implies being able to use the same syntax. You have to dereference b to get at a. You can also change the value of be (so it doesn't have to point to a at all).

    That may be technically and formally correct (*), but when people ask questions such as "Does C have references?", they probably mean the C++ language feature referred to as "references" (reference variables).

    I'm just using it to illustrate the idea things as references to blocks of memory.

  • I do think it's fair to say that "C references" (in your parlance), C++ reference variables / C# "ref locals", C#/Python/Java/JavaScript references all refer (ha!) to related concepts which are not identical.

    https://www.tutorialspoint.com/cplusplus/cpp_references.htm

    "Think of a variable name as a label attached to the variable's location in memory. You can then think of a reference as a second label attached to that memory location. Therefore, you can access the contents of the variable through either the original variable name or the reference."

    (It's saying what I'm saying, basically.)

  • https://stackoverflow.com/a/45994242

    --

    What a confusing use of terms!

    To clarify,

    1. for a method foo(int[] myArray), "passing a reference (object) by value" actually means "passing a copy of the object's address (reference)". The value of this 'copy', ie. myArray, is initially the Address (reference) of the original object, meaning it points to the original object. Hence, any change to the content pointed to by myArray will affect the content of the original object.

      However, since the 'value' of myArray itself is a copy, any change to this 'value' will not affect the original object nor its contents.

    2. for a method foo(ref int[] refArray), "passing a reference (object) by reference" means "passing the object's address (reference) itself (not a copy)". That means refArray is actually the original address of the object itself, not a copy. Hence, any change to the 'value' of refArray, or the content pointed to by refArray is a direct change on the original object itself.

    Which is what I said.

  • Remember in Monkey C you're not dealing directly with pointers, numbers, etc..  Just objects.  In the case of an array, it's a collection of other objects.  So. "x" above is put on the call stack and a copy is seen in f() as "arr", but it's a different object than "x" (a copy), but the elements of "arr" are exactly the same objects as in "x" .  So when you modify one of those objects using "arr", you see that in "x".

    Yes. These objects work like structures in C. An "int" object in Monkey C is a structure that include type information as well as the actual value. (Monkey C doesn't have "pointers": memory address value that you can change).

    In C. you can only pass the address of an array. In Monkey C, you pass a structure (object) that has the address of the array but also it's size (extent).

  • What a beautiful discussion :)

    class test
    {
        var mX;
        
        function initialize(x){ mX=x;}
    }

    function f(_)
        {
            _.mX = 0;
        }

        function x()
        {
            var x = new test(12);
            SYS.println(x.mX);
            f(x);
            SYS.println(x.mX);

       }

    console:

    12
    0

    and again, inside f was modified

    but

    function f(_)
        {
            _ = 0;
        }

        function x()
        {

            var x = 12;
            SYS.println(x);
            f(x);
            SYS.println(x);

    produces:

    12

    12

    ok, so it means that passing object to function  working as pointer/by_ref and primitives aren't object and it also run when I save object in members. So it's possible eg. access data one object form other

    class c_1

    {

    var ref_to_x;

      function initialize(rx){ref_to_x = rx;}

      function print_ref() {SYS.println(ref_to_x);}

    }

    class _2

    {

      var x, _1;

      function initialize()

      {

        x = [0,0];

       _1 = new c_1(x);

       _1.print_ref();

       x [1] = 1; x[0] = 1;

       _1.print_ref();

      }

    }
           

    prints

    [0,0]

    [1,1]

  • Which is what I said.

    Sure, but I think you also said that the Microsoft page on passing arrays was contradicting itself by talking about "passing references by value", and I also understood you to say "passing references by value" is not a useful concept.

    I'm just trying to say that in some contexts, there are two separate concepts under discussion:

    - Value type vs. reference type: e.g. in C#: int vs int[]. In JavaScript: number vs object. In Monkey C: Number vs Array. In the case of "references" in Monkey C, JavaScript/Python/C#, I don't care whether what's actually being passed around *internally* is a pointer to an object, or a struct that has the type, address, and array size when applicable. The effect is the same. Roughly speaking (sorry for not being formal), when you pass a value type to a function, it gets a copy of the content (e.g. an integer). When you pass a reference type it gets a "reference" to the content (e.g. an array of integers). In other words:

    var x = ...;
    var y = x; /* If x is a value type, y gets a copy of x's content (if x's value is changed -- not reassigned -- y's value is unchanged. If x is a reference type, y gets a reference to x's content (if x's value is changed -- not reassigned, then y's value also changes.) */

    - Pass by value vs. pass by reference: Pass by reference: if I pass the variable x to a function, that function can reassign x to a different value that will be seen by the caller. Pass by value: if I pass the variable x to a function, that function cannot reassign x.

    void foo(ref int a, b) {
      a = b;
    }

    void foo(int a, b) {
      a = b;
    }

    void test() {
      int v = 1;
      int x = 2;
      int y = 3;
      int z = 4;
      /* v, x, y, z are all value types; you can't "change" any of their values anyway, only reassign them (I'm speaking conceptually, not in terms of memory addresses). This is why in languages like JavaScript, it's said that primitives are immutable. If you say "let x  = 42" in js, then subsequently say "x = 13", that's considered a reassignment and not a change to the original value, even if the memory address of x remains the same. Obviously in languages like JavaScript you're not meant to care about memory addresses. And in C#, pointers are unsafe because the CLR can dynamically move things around in physical memory, so pointers can only be used with care.
    */

      foo(v, x); // v has been reassigned to the value of x
      foo2(y, z); // y is unchanged
    }

    --

    In a languages like C# and C++ you have all 4 combos of the 2 concepts (although pass * by value is the default semantics):
    - Pass value by value, pass value by reference, pass reference by value and pass reference by reference

    In JavaScript and Monkey C, you only have:
    - Pass value by value, pass reference by value

  • Remember in Monkey C you're not dealing directly with pointers, numbers, etc..  Just objects.  In the case of an array, it's a collection of other objects.  So. "x" above is put on the call stack and a copy is seen in f() as "arr", but it's a different object than "x" (a copy), but the elements of "arr" are exactly the same objects as in "x" .  So when you modify one of those objects using "arr", you see that in "x".

    Yes. These objects work like structures in C. An "int" object in Monkey C is a structure that include type information as well as the actual value. (Monkey C doesn't have "pointers": memory address value that you can change).

    In C. you can only pass the address of an array. In Monkey C, you pass a structure (object) that has the address of the array but also it's size (extent).

    Sure, that's pretty clear from Monkey C's duck-typed nature, the presence of Array.size() and from looking at the size of arrays in the memory viewer. (IIRC there's like 10 bytes of overhead for each array).

    I don't think the 2 of you are saying the exact same thing though. It sounds like Jim is saying that passing an array to to a function would duplicate the entire array (with references to all the objects), whereas you (dpawlyk) are saying that it's just the struct with the array type, size, and pointer to contents that's being duplicated. I would say that the latter is far more plausible, due to memory and efficiency concerns.

    EDIT: I mean to say that Jim's description is somewhat unclear (I see the irony), not that he doesn't know how arrays are passed in Monkey C.

  • Sure,...

    I said it a couple of times.

    ...but I think you also said that the Microsoft page on passing arrays was contradicting itself by talking about "passing references by value",

    I misread the MS link (it was a bit confusing in spots).

    It sounds like Jim is saying that passing an array to to a function would duplicate the entire array (with references to all the objects),

    This isn't happening. (I pass arrays to functions to sort them.)

  • This isn't happening. (I pass arrays to functions to sort them.)

    I know that's not what's happening. I was just trying to clarify that part of the discussion. It would be a bad design for many reasons to pass arrays like that.

    EDIT: I shouldn't have said 'the latter is far more plausible". I should've said "the latter is how it works."

  • EDIT: I mean to say that Jim's description is somewhat unclear (I see the irony), not that he doesn't know how arrays are passed in Monkey C.

    I'd lay money on him (and you) knowing how arrays are passed in Monkey C.

    If you say "let x  = 42" in js, then subsequently say "x = 13", that's considered a reassignment and not a change to the original value, even if the memory address of x remains the same.

    x and 42 are two separate things. The assignment is an instruction to copy the 42 to the memory pointed/referred to by x (so, you have the 42 data in two places after the assignment).

    Assigning 13 to x is a different copy. The 42 still exists (it's not being overwritten).

    Roughly speaking (sorry for not being formal), when you pass a value type to a function, it gets a copy of the content (e.g. an integer). When you pass a reference type it gets a "reference" to the content (e.g. an array of integers).

    Which pretty-much matches what I was saying.

    For values, the value gets copied to a new block of memory and the address/reference to that memory is provided to the function.

    For references, the address/reference to the original memory is provided to the function.