1. 6
  1. 2

    The same applies for Java as well. Java’s reference types don’t get passed by reference. Instead, the variables are effectively pointers, and the pointers get passed by value. It’s a subtle distinction but an important one when you’re talking about programming language design.

    1. 2

      Barbara Liskov (for the CLU language) termed this call by sharing, where the callee gets references to the arguments but can’t change what they refer to. A nice thing is that you can understand primitives (that might be passed by value as an optimisation) in the same way, as long as you lack reference equality. Since they’re immutable you can’t change them and discover that they aren’t actually shared!

      Nowadays most people just understand it as ‘references passed by value’, which is less fun. ☺️

      1. 2

        The term call by sharing still reveals a fundamentally mechanistic conception of argument passing. A better way to think about it is to make a distinction must be made between values, which exist in the semantics of a programming language (which is a timeless mathematical object, thus the question of whether it’s mutable doesn’t even make sense), and representations, which exist in computer memory (which obviously exists in time and might mutate). Now things become clearer: there is always a single number 42 and a single string “Hello, world!”, but they may be represented arbitrarily many times in computer memory.

      2. [Comment removed by author]

        1. 6

          The litmus test is to write a swap function/method.

          T a = foo;
          T b = bar;
          swap(a,b);
          assert (a == bar);
          assert (b == foo);
          

          You can do that in C++, but not in Java. We assume that == does a pointer comparison here.

          Sometimes that is very useful (swap(foo[11], foo[42])), but it is also nice if a function call can never change your local variables.

          1. [Comment removed by author]

            1. 6

              I don’t know that sugar is a great way to describe it. “Liability”, is probably better. What I’ve seen happen is that people are surprised by the fact that they expect to be passing a copy, but in fact are passing a pointer to the value without an explicit, call site, indicator.

            2. 2

              You can write swap in C (not generically, of course), though:

              int a = foo, b = bar;
              swap_ints(&a, &b);
              assert (a == bar);
              assert (b == foo);
              

              The problem in Java is it doesn’t simultaneously have types “T” and “reference to T”.

              1. 7

                Doesn’t that specifically fail the litmus test? Note that qznc’s code has swap(a, b) but your code has swap(&a, &b). qznc is demonstrating pass-by-reference while your code is demonstrating pass-pointer-by-value, no? (Generics seems like a distraction here.)

                1. 1

                  AFAICT, pass-by-reference is syntactic sugar for specific use cases of pass-pointer-by-value.

                  I agree that genericity is a distraction, but someone could have said “strictly speaking, it’s not the same because…” That’s why I mentioned it in parentheses.

                  1. 1

                    I would say pass-reference-by-value is a workaround for the lack of pass-by-reference.

                    There is one advantage with C++ call-by-reference: The parameters cannot be NULL. The compiler complains about stuff like std::swap(NULL,NULL). There is need to check for NULL in the function.

                    1. 1

                      Wouldn’t a much simpler solution be to eliminate null pointers from the language definition?

                2. 1

                  Slightly off-topic, but you can do this, and it’s pretty generic:

                  #define swap(a, b) do {    \
                      __auto_type _a = &(a); \
                      __auto_type _b = &(b); \
                      __auto_type _t = *_a;  \
                      *_a = *_b;             \
                      *_b = _t;              \
                  } while (0)
                  

                  This of course has some downsides.

                  1. 1

                    That’s not genericity, it’s boilerplate generation. Litmus test: Can a C compiler perform semantic analysis (e.g., checking that variables are in scope) on pre-preprocessed code?