Alex
Alex

Reputation: 55

Function arguments passed by in C++ vs in Java

I'd be glad if you can give me an answer. I know that Java is only pass by value while C++ is pass by value but also pass by reference. I'll post below some codes in order you to understand what my confusion is.

Pass by value in C++ :

void modify(int x, int y){
  x=10;
  y=20;
}
void main(){
  int a=5,b=8;
  cout << a; //outputs 5
  cout << b; //outputs 8
  modify(a,b);
  cout << a; //still outputs 5
  cout << b; //still outputs 8
}

modify(a,b); -> the parameters are called actual parameters(the parameters passed to a function) and from void modify(int x, int y) -> the parameters are called formal parameters(the parameters received by a function).

All the 4 parameters: a,b and x,y have different memory locations. When the line modify(a,b); is reached, the formal parameters(x and y) will have a copy of the values of the actual parameters(a and b).In other words, x will be 5 and y will be 8, but by reaching those lines:

x=10; y=20;

the values of the formal parameters will be changed to 10 and 20, respectively. After that, the modify function will be deleted from the Stack, getting back to the main method where the actual parameters(a and b) will still have the same values: a=5 and b=8.

This is pass/call by value and it aplies to Java too.

NOW, regarding pass/call by reference (only in C++):

void modify(int* p) {
    *p = 10;
}
void main()
{
    int a = 5;
    int* p = &a;
    modify(p);
    cout << a << endl; //a is now 10.
}

From what I've understood so far, this is call by reference and it can be done using pointers. By reaching the line modify(p); we passed as an argument the address of "a" which is stored by "p", so in this case, by having the reference as an argument in the function void modify(int* p), we accessed "a" at that memory location and by reaching this line: *p=10;(de-referencing) we set the value of "a" to be 10.

My question is: Why Java isn't considered pass by reference as well, because I can see that it acts the same as in the case of C++? I've seen the code below posted on another question regarding Java and I'll also post the answer of that person which confused me more.

public static void main(String[] args){
            Dog myDog = new Dog("Rover"); //myDog is a reference, a pointer to the object in memory
            foo(myDog); //you're passing the address of the object
    }

//Suppose the Dog object resides at memory address 42. This means we pass 42 to the method.

    public void foo(Dog someDog) {
    someDog.setName("Max");     // AAA
    someDog = new Dog("Fifi");  // BBB
    someDog.setName("Rowlf");   // CCC
    }

    /*Let's look at what's happening.
        the parameter someDog is set to the value 42
        at line "AAA"
            someDog is followed to the Dog it points to (the Dog object at address 42)
            that Dog (the one at address 42) is asked to change his name to Max
        at line "BBB"
            a new Dog is created. Let's say he's at address 74
            we assign the parameter someDog to 74
        at line "CCC"
            someDog is followed to the Dog it points to (the Dog object at address 74)
            that Dog (the one at address 74) is asked to change his name to Rowlf
            then, we return

Did myDog change?
        There's the key.
        Keeping in mind that myDog is a pointer, and not an actual Dog, the answer is NO. myDog still has the value 42; it's still pointing to the original Dog (but note that because of line "AAA", its name is now "Max" - still the same Dog; myDog's value has not changed.)
     If Java had pass-by-reference semantics, the foo method we defined above would have changed where myDog was pointing when it assigned someDog on line BBB.*/

From what I've noticed as in the case of C++ where we changed the value of "a" from 5 to 10, here in Java, by setting the name of the dog from Rover to Max, isn't it also call by reference?

By looking at this statement:

/*If Java had pass-by-reference semantics, the foo method we defined above would have changed where myDog was pointing when it assigned someDog on line BBB.*/

I applied this also in C++ based on the previous example:

void modify(int* p) {
    *p = 10;
    int b = 20;
    p = &b;
}
void main()
{
    int a = 5;
    int* p = &a;
    cout << p << endl; //OUTPUTS memory address 2002(e.g. let's say)
    modify(p);
    cout << a << endl; //a is now 10.
    cout << p << endl; // ALSO OUTPUTS the same memory address 2002
}

but "p" doesn't point to the address of "b" when exiting the modify function.

That's my confusion, because based on the line If Java had pass-by-reference semantics, the foo method we defined above would have changed where myDog was pointing when it assigned someDog on line BBB. and applying the same in C++, it results that neither JAVA or C++ has pass by reference, but only pass by value. If you can tell me why Java doesn't have pass by reference when it acts like in C++ as I can see( example with the DOG ), I'd be grateful !

Upvotes: 0

Views: 266

Answers (1)

newacct
newacct

Reputation: 122429

The biggest problem when talking about "pass-by-whatever" is different people have different definitions for these terms. So I will start by giving my definition of pass-by-value and pass-by-reference for the purposes of this answer. A function parameter is pass-by-value if direct assignment to the parameter inside the function does not have an effect on the passed variable in the calling scope. A function parameter is pass-by-reference if direct assignment to the parameter inside the function have the same effect as direct assignment to the passed variable in the calling scope.

Under this definition, Java (as well as many other languages like C, JavaScript, Python, Ruby, Scheme) are always pass-by-value. Under this definition, C++ is always pass-by-value when the function parameter has & (including both the C++ examples you put here), and is always pass-by-value when the function parameter does not have &. Your second C++ example is pass-by-value because if you assign to p directly (i.e. p = something;) inside modify(), it has no effect on the calling scope. In modify(), you never assigned to p directly; you instead dereferenced p using the * operator, and assigned to the result of that. That is not the same thing as assigning to p.

The biggest difference between C++ and Java are what types are available. The only types in Java are primitives types and reference types. The values of a reference type are "references", i.e. pointers to objects. There are no "object types", so the value of a variable cannot be an object directly. There are no pointers to primitives, or pointers to pointers to objects, or other combinations of pointers.

Your Java example:

public static void main(String[] args) {
    Dog myDog = new Dog("Rover");
    foo(myDog);
    // here, "myDog" points to the first Dog object, and has the name "Max"
}

public static void foo(Dog someDog) {
    someDog.setName("Max");
    someDog = new Dog("Fifi");
    someDog.setName("Rowlf");
}

is equivalent to this C++ code (ignoring the memory management aspect):

void main(void) {
    Dog *myDog = new Dog("Rover");
    foo(myDog);
    // here, "myDog" points to the first Dog object, and has the name "Max"
}

void foo(Dog *someDog) {
    someDog->setName("Max");
    someDog = new Dog("Fifi");
    someDog->setName("Rowlf");
}

Both of these examples are pass-by-value, as they both assign to the parameter directly (someDog =), and in both of these cases, they have no effect on the calling scope -- they both just change the pointer inside the function to point to a different object, but they do not affect what the pointer in main points to. (Note that the syntax is a little different: the equivalent of the Dog type in Java is the Dog * type in C++, and the equivalent of -> in C++ is . in Java.)

C++ has object types, where the value of a variable can be an object itself. In this case, a parameter of this type would mean that the object is copied when passing:

void main(void) {
    Dog myDog("Rover");
    foo(myDog);
    // here, the Dog object in the local variable "myDog" has the name "Fifi"
}

void foo(Dog someDog) {
    // this calls the object's assignment operator, which by default
    // copies all the fields
    someDog = Dog("Fifi");
}

There is no equivalent to this in Java, as Java has no object types. Objects are always manipulated through a reference (pointer to object).

You can also pass an object by reference in C++, like this:

void main(void) {
    Dog myDog("Rover");
    foo(myDog);
    // here, the Dog object in the local variable "myDog" has the name "Fifi"
}

void foo(Dog &someDog) {
    // this calls the object's assignment operator, which by default
    // copies all the fields
    someDog = Dog("Fifi");
}

Here, direct assignment to the parameter (someDog =) has the same effect as the same assignment in the calling scope. Java has no equivalent as it has neither object types nor pass-by-reference.

You can also pass a pointer to the object by reference:

void main(void) {
    Dog *myDog = new Dog("Rover");
    foo(myDog);
    // here, "myDog" points to the second Dog object, and has the name "Fifi"
    // the first Dog object still has the name "Rover"
}

void foo(Dog *&someDog) {
    someDog = new Dog("Fifi");
}

Here, direct assignment to the parameter (someDog =) has the same effect as the same assignment in the calling scope, which causes the pointer to point to a different Dog object. Java has no equivalent as it does not have pass-by-reference. However, there are some languages with similar types as Java but which have pass-by-reference. For example, C# does pass-by-reference if the parameter is marked ref or out, and PHP does pass-by-reference if the parameter is marked &. Here is the equivalent code in C#:

static void Main() 
{
    Dog myDog = new Dog("Rover");
    foo(ref myDog);
    // here, "myDog" points to the second Dog object, and has the name "Fifi"
    // the first Dog object still has the name "Rover"
}
static void foo(ref Dog someDog)
{
    someDog = new Dog("Fifi");
}

Upvotes: 1

Related Questions