Welcome back to my series, where I go over the little java quirks and obstacles that I encountered on my journey. In this installment I will discuss one of the concepts that I struggled to wrap my head around and that is: reassigning an parameter variables. I am referring specifically to reassigning object parameters because the concept of mutability only applies to non-primitive data types.
I'll begin by describing what I was trying to do and later on I will explain why it did not work.
The Problem π’
There came a time where I decided it was a good idea to reassign an object inside of a method. I was trying to be clever and Java just did not want to play along. The method went something along the lines of...
public static void process(Contact[] arr) {
Contact[] result;
boolean condition;
//traverse the array
int i = 0;
for (String element: arr) {
condition = someCriteria(element);
if (condition) {
result[i] = element;
i++;
} // if
} // loop
arr = result;
} // remove method
public static void main(String[] args) {
Contact[] mydata = readInContacts();
process(mydata);
}
At first glance, you may get the impression that this code is flawless, after all it was written by myself π. The program reads in text from a CSV file and creates contact objects from it. I then took that list of contact objects and made an array out of them. My aim was to create an impure method, process()
, that filters out objects in an array that met some criteria. The intention was to create a new array of a different size and assign that new array to the parameter, thinking that it would make those changes to the original argument. When the code was run, it left the argument unchanged.
You can try and find out what is wrong with it but I think its pointless unless you really have a thorough understanding of Java. The error is on the 3rd line of code from the bottom (arr = result
). Let me explain, when you reassign a parameter variable, it does not make any changes to the argument variable. Java will not throw an error or tell you that what you are doing is illegal. You will just have to suffer there in silence, questioning logic and your ability to code altogether.
So just to be clear...
public static void modify(int[] args) {
data args = new int[]
}
public static void main(String[] args) {
int[] myarr = new int[] {1,2,3,4,5,6};
modify(myarr);
System.out.println(Arrays.toString(myarr)); // [1,2,3,4,5,6,7]
myarr = new int[] {1,2,3}
System.out.println(Arrays.toString(myarr)); // [1,2,3]
}
The modify
method will not make any changes to the myarr
array because you cannot reassign an argument inside of a method.
Note: π You may want to familiarise yourself with the concept of mutability before continuing. Knowing the difference between pure and impure methods should suffice.
Parameter vs Argument
I often hear the words argument and parameter used interchangeably even though they are not the same thing. To avoid confusion I'll define an argument, a parameter, and help you distinguish between them.
An argument is a variable, which usually holds a value of the variables data type, that you pass into a method. A parameter is an alias or copy of the argument, and if it is of a reference data type then we can use it to manipulate the argument inside the scope of a method that it was passed into.
If we call this greet
method and pass in the argument name
, like so greet(name)
, then we say name
is the argument that was passed into the greet
method. aName
is what we call the parameter. Whenever greet is called with an argument, aName
will take on the value of that argument. The argument and the parameter are separate entities. The parameter is a temporary alias of the argument that only exists inside the scope of the method that uses it.
Hint: π‘ It is good practice to name parameter variables with an "a" prefix to the name of the argument. It helps, whoever is reading the code, keep track of which variables are arguments and which ones are parameters as well as which arguments are assigned to which parameters.
Parameters, like variables, can be a primitive or a reference data type. Java handles them differently in each case.
When parameters are primitive
When parameters are of a primitive data type then Java will simply create a separate copy the value the argument in memory.
The parameters and arguments are separate entities in this case. If the paramater, aName
, is changed in any way, it will not affect the argument. When the value in address A changes, it has no effect on the value in address B.
When parameters are non-primitive(reference data type)
When dealing with reference data types, variables do not store the object assigned to it, but it stores a pointer which has the address of where the object is stored in memory.
When parameters are of a reference data type then Java will not create a separate copy of the object in memory but it will create a separate copy of the pointer argument.
It is because we are dealing with pointers that we have the power of mutability. If 2 pointers point to the same address (object) in memory and either one makes changes to it, then the other will reflect those changes. This means that by changing the attributes of objects that are referenced by parameter then the object referenced by the argument variable will reflect those changes. This is because both the parameter and argument will point to the same object the same object in memory.
In other words, if the parameter variable, arr
makes changes to the array that it references in address A then the argument myarr
will also have those changes because they reference the same object
However... If you decide to change the address that the parameter points to, by assigning a parameter to a new object all together, then the parameter and the argument will no longer point to the same object meaning that they will become separate entities, and any changes made to one will not affect the other. To be clear, if you reassign an object parameter you are changing the address that parameter points to.
If we assign the parameter, arr
to a new array, which is stored in Address B, we will no longer be able to mutate or make changes to the argument by changing the parameter.
The Solution π‘
There are many ways to work around this issue that I had, it all depends on the situation. I had to resort to changing the filter()
method by returning the filtered array and use the object = object.method()
syntax to store the result parameter and store that in the argument. I know it is not the most elegant solution but I was pressed for time. I should have actually used a LinkedList because by doing so, I would have been able add and remove objects from my List by using the .add()
and .remove()
methods on the parameter and it would mutate the argument, meaning there would be no need for the reassignment of the parameter. Alternatively, I could have declared a global variable that I would manipulate inside any method, removing the need for a parameter and argument to reference the object of interest.
Summary
Any changes made to a parameter variable within a method mutates the original argument, provided that they are of a reference data type. This happens because both the argument and parameter point to the same object in memory. When you reassign a parameter variable, you are changing the object that it references in memory and so it will not make any changes to the argument.
The concept of mutability is powerful, that is if you know how it works and when to use it. Mutability allows us to make code that is more intuitive and self explanatory. sort(list)
is much easier for beginners to interpret than list = sort(list)
. This problem I had is just one of those corner cases that I thought could have done with better explaining. It would have saved me a lot of time.
As always thanks for the read and Happy Coding π»!
Top comments (0)