Java is pass-by-value. How could you modify the language to introduce passing by reference (or some equivalent behavior)?
Take for example something like
public static void main(String[] args) {
String variable = "'previous String reference'";
passByReference(ref variable);
System.out.println(variable); // I want this to print 'new String reference'
}
public static void passByReference(ref String someString) {
someString = "'new String reference'";
}
which (without the ref
) compiles to the following bytecode
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String 'previous String reference'
2: astore_1
3: aload_1
4: invokestatic #3 // Method passByReference:(Ljava/lang/String;)V
7: return
public static void passByReference(java.lang.String);
Code:
0: ldc #4 // String 'new String reference'
2: astore_0
3: return
The code at 3:
loads the reference onto the stack from the variable variable
.
One possibility I'm considering is to have the compiler determine a method is pass by reference, possibly with ref
, and change the method to accept a Holder object which stores the same reference as our variable. When the method completes, and possibly changes that reference in the holder, the variable on the caller side's value is replaced with the holder reference's value.
It should compile to an equivalent of this
public static void main(String[] args) {
String variable = "'previous String reference'";
Holder holder = Holder.referenceOf(variable);
passByReference2(holder);
variable = (String) holder.getReference(); // I don't think this cast is necessary in bytecode
System.out.println(variable);
}
public static void passByReference(Holder someString) {
someString.setReference("'new String reference'");
}
where Holder
might be something like
public class Holder {
Object reference;
private Holder (Object reference) {
this.reference = reference;
}
public Object getReference() {
return this.reference;
}
public void setReference(Object reference) {
this.reference = reference;
}
public static Holder referenceOf(Object reference) {
return new Holder(reference);
}
}
Where can this fail or how could you improve it?
To answer your question:
Where can this fail?
this
new
...and possibly others. Basically, your ref
keyword must only be usable if the parameter source is a non-final field or local variable. Any other source should generate a compilation error when used with ref
.
An example of (1):
final String s = "final";
passByReference(ref s); // Should not be possible
An example of (2):
passByReference(ref this); // Definitely impossible
An example of (3):
passByReference(ref toString()); // Definitely impossible
passByReference(ref new String("foo")); // Definitely impossible
An example of (4):
passByReference(ref "literal"); // Definitely impossible
And then there are assignment expressions, which seem to me like something of a judgement call:
String s;
passByReference(ref (s="initial")); // Possible, but does it make sense?
It's also a little strange that your syntax requires the ref
keyword for both the method definition and the method invocation. I think the method definition would be sufficient.