Student: So I was thinking about how we just saw a builder example again. My friend told me they never write methods that make new arrays because it’s inefficient, they just write methods that change the arrays.
Prof: Your friend sounds very opinionated.
Student: They know so much stuff! It’s hard to argue with them.
Prof: Well, you can take it on my authority that both kinds are useful; we should study the kind that changes arrays now. We can do the same thing as before, but instead of returning a new array, we can change the one stored in the record. Sometimes we call this an update or an in-place update of the array.
Student: OK great now I’ll be able to compare them myself.
Prof: So, we had
discounted in the last step. Let’s write discountInPlace. What do you think the return type should be?Student: Ummm,
int[] again?Prof: So our goal here is to write a method that changes the existing array, rather than returning a new one. Do we know a type for methods that have effects and don’t return anything?
Student: Ummm.
void?Prof: Right. So let’s set up the method with a
void return type, and try to change the existing array without making a new one.Student: Wait what’s that
I@ thingProf: Ah, that’s how Java prints arrays. The
I means int, and the @ followed by the numbers is a reference number made by Java. By default this is what Java shows when you print an array – it prints its reference!Student: Interesting. OK. Back to the code. So instead of having a new
result and filling that in, you just… change the pricesCents? And that works?Prof: Let’s see! How do we call it?
Student: I guess…
menu.discountInPlace()?Prof: Great idea. It turns out we aren’t allowed to write a method call outside of a definition at the top level! So if we just write
menu.discountInPlace() we’d get a syntax error. void-returning methods have to be called from another method body – main works. Have a look at this program; do you notice anything interesting about the output?Student: Whoa, the contents of
regular changed?Prof: That’s right.
main ran and called discountInPlace, and that changed the contents of the array stored in regular. Here’s a memory diagram of what things look like in the middle of the loop for this program:Names (the stack)
menu.discountInPlace() on @1002index = 2p = 500main()top level
regular = @1001menu = @1002Heap
@1001: [2000 1800, 1000 900, 500, 800]@1002: Menu[pricesCents=@1001]Student: Huh so that
@1001 is referred to by… regular, and by the pricesCents field. And so that reference is being used in the loop?Prof: That’s right, and that’s why you see the object reference
@1002 in the frame header. That was the receiver for the method call, and so we know that pricesCents is referring to the field of that object.Student: That… went a little over my head.
Prof: So when we use
pricesCents in the body of the loop, it has to refer to some value. It isn’t a parameter of the method; it’s a field of the receiver we called it with. The receiver is @1002, and its pricesCents field is @1001, so that’s how that lookup occurs.Student: OK, I think I kind of get it. I definitely understand that there is only one array made in this example, and it’s changing inside the method.
Prof: That’s a good lesson to take from this conversation. This is called an updater method for an array.
Practice
This Menu has both methods from this chapter. The builder runs first, at the top level, then main runs the updater:
record Menu(int[] pricesCents) {
int[] discounted() {
int[] result = new int[pricesCents.length];
int index = 0;
for(int p: pricesCents) {
result[index] = p * 90 / 100;
index += 1;
}
return result;
}
void discountInPlace() {
int index = 0;
for(int p: pricesCents) {
pricesCents[index] = p * 90 / 100;
index += 1;
}
}
}
int[] regular = { 2000, 1000, 500, 800 };
Menu menu = new Menu(regular);
int[] sale = menu.discounted();
void main() {
menu.discountInPlace();
}How many arrays does this program create in total?
What does each array hold once
main finishes?regular =
sale =
sale =
While
discountInPlace runs, which top-level names hold the same reference as pricesCents?regularsalesaleholds the array the builder made, a separate reference. Oncemainfinishes it has the same contents asregular, but==between them isfalse.menumenuholds a reference to theMenurecord. That record’s field holds the array’s reference, butmenuitself does not.