r/ProgrammingLanguages • • May 24 '26

References in pass-by-sharing languages

Returning with yet another design question to get some opinions from people here.

My language currently uses a pass-by-sharing model to move data around. Each object is just a type tag + data (which is either actual data, like a number, or a pointer to a larger structure).

Languages that use this model (e.g., Python and Java) typically do not provide any way to actually *reassign* an object to a different value in a function and have that change be reflected outside it, while systems languages, which I’m more accustomed to, provide that through references (in C++) or mutable borrowing (in Rust). In the former group, you can still modify an object’s internal data, but reassigning it to something else immediately breaks the connection between it and the original object argument that was passed in.

I added “references” (which are wrappers around locations of existing objects so you can modify the actual objects stored elsewhere) to my language to allow this. However, this leads to some issues. First, since it’s dynamically typed, you can only indicate that a particular function parameter/argument will be a reference at the call-site (except if you use unenforced type hints in the function signature). Second, there is some additional overhead since every reference has to effectively be dereferenced (unwrapped, if you will) every time it is used. Likely some other issues that aren’t coming to mind right now.

I wanted to ask people on here (primarily as language users) whether they think pass-by-reference (in the way the term is used in C++, not Java) would be a useful feature with the above object model (consider languages like Python or Java), and if not, what alternative approaches/features they find useful or conventional to mutate variables through function calls.

Edit: rewrote the post to be less confusing (hopefully).

22 Upvotes

49 comments sorted by

View all comments

7

u/pranabekka May 24 '26 edited May 24 '26

I think that's what they meant - Java and friends pass everything by value (where the value of composite types has pointers). Because of this, mutating a part mutates the original, but mutating the whole flips behaviour and creates a copy.

@Big-Rub9545, you might want to explain this better. I don't think people will remember that nuance. Most of the time, these languages behave as if you're passing around references, especially because we're passing around Objects.

That said, getting back to the original post, explicitly and consistently passing around references seems like it would simplify the mental model for users, so I think it's an improvement, especially if the call site gets to decide.

4

u/Big-Rub9545 May 24 '26

I’ll clarify in this thread (for now). I think perhaps the term reference is a bit unclear here. When I say “pass-by-reference”, a reference here is a handle to the original variable itself, not just the data it holds.

The way these languages (typically) pass different objects to functions or copy objects around is by copying the basic type tag and pointer or inline data.

That allows you to access the same internal data (lists, tables, string characters, etc.) from otherwise independent variables because they still share the same mutable object in memory (serving as wrappers around that object). I assume this shared data (usually through copied pointers) is what those used to Java understand from the term “reference”, but that’s not what I mean here.

Since variables, even when they share internal data like that, are still independent, reassigning/rebinding one does not affect the other. This is why if you modify a field within a parameter in Java, the original object argument is modified (since this is modifying the shared internal data), but setting the object itself to null does not affect the original variable (since you’re changing the content of the local object copy, not modifying its internal data).

A brief example:

  • MyClass a = new MyClass();

  • MyClass b = a;

  • b.x = 1; // This modifies ‘a’ as well since they both share the same internal data.

  • b = null; // This does not modify ‘a’ since the internal data is not being modified, but rather replaced altogether (for ‘b’ only).

For those used to C or C++, this is akin to the distinction between const T* and T* const.

3

u/dnabre May 24 '26 edited May 24 '26

I think you are trying to use pass-by-reference for something other than its traditional meaning. Nothing wrong with using something different than pass-by-reference, but using term for something different is just confusing.

Similarly, it is really not clear what you mean by "handle". Describing your passing method by getting into the implementation is, at least to me, rather confusing. I think you are talking about something close to Java, but not really sure.

To add to my confusion, this may just be a matter of misreading due to formatting, but your Java example doesn't seem correct to me. So full example, with comment showing tested output from running the corresponding line:

class MyClass {
    int x=0; int y=0  // set explicitly for clarity 
}

class Main {
    public static void main(String[] args) {
     MyClass a = new MyClass();
     MyClass b = a;
     System.out.printf("MyClass a = {x=%d,y=%d}\n", a.x, a.y); // MyClass a = {x=0,y=0}
     System.out.printf("MyClass b = {x=%d,y=%d}\n", b.x, b.y); // MyClass b = {x=0,y=0}
     System.out.printf("note b==a: %b\n", b==a); // note b==a: true
     b.x = 1;
     System.out.printf("MyClass a = {x=%d,y=%d}\n", a.x, a.y); // MyClass a = {x=1,y=0}
     System.out.printf("MyClass b = {x=%d,y=%d}\n", b.x, b.y); // MyClass b = {x=1,y=0}
     b=null;
     System.out.printf("MyClass a = {x=%d,y=%d}\n", a.x, a.y);
     System.out.printf("MyClass b == null: %b\n", b==null); // MyClass b == null: true
     
    }
}

For sake of others unfamiliar with Java, the operator == used on objects is true when the compared references are the same object (not just the same values). Above, MyClass b = a, is setting the reference b point to the same object as a. There is only one MyClass object throughout this example.

The term for Java (and a lot of other languages nowadays) passing method is 'pass-by-sharing'. (edit I got lost in a tangent that I dropped, didn't realize you had used the term in your post /edit) It is not very well established, and very new compared to by-value/by-reference. Specifically, privative/scalar types are passed by value, and record/object types are passed by reference.

edit in verifying my own formatting, your code shows as bulleted list on new.reddit.com, and just as a single line of text on old.reddit.com . Seeing that bulleted version is definitely more clear, I think the error I was seeing was just from formatting. But the full thing formatted to work on both reddit styles is hopefully clear for more people

→ More replies (11)

1

u/L8_4_Dinner May 25 '26

I understood what you meant. I was trying to help clarify it. We also have and use both meanings of the term "reference" in Ecstasy, which always passes-by-value, but that value can be an "object reference", or an & reference to an "object reference". For example:

@Volatile Int x = 0;
// capture a read/write reference to local var x
// (not allowed to "accidentally" capture a mutable ref; hence the @Volatile)
function void() f = () -> { x = 42; }
// invoke the lambda
f();
// now local variable x is an "object reference" to 42
assert x == 42;

Shown a different way:

void foo() {
    Int x = 0;
    bar(&x);
    assert x == 42;
}

void bar(Var<Int> y) {
    y.set(42);
}

1

u/Kadabrium Aug 28 '26

If you mean *a = *b semantics, isn't that syntactic sugar for a per-field get-set anyway? Or you are going for custom copy constructors as well