Pass by reference or pass by value?

When learning a new programming language, one of the possible roadblocks you might encounter is the question whether the language is, by default, pass-by-value or pass-by-reference.

So here is my question to all of you, in your favorite language, how is it actually done? And what are the possible pitfalls?

Your favorite language can, of course, be anything you have ever played with: popular, obscure, esoteric, new, old...


Here is my own contribution for the Java programming language.

first some code:

public void swap(int x, int y)
{
  int tmp = x;
  x = y;
  y = tmp;
}

calling this method will result in this:

int pi = 3;
int everything = 42;

swap(pi, everything);

System.out.println("pi: " + pi);
System.out.println("everything: " + everything);

"Output:
pi: 3
everything: 42"

even using 'real' objects will show a similar result:

public class MyObj {
    private String msg;
    private int number;

    //getters and setters
    public String getMsg() {
        return this.msg;
    }


    public void setMsg(String msg) {
        this.msg = msg;
    }


    public int getNumber() {
        return this.number;
    }


    public void setNumber(int number) {
        this.number = number;
    }

    //constructor
    public MyObj(String msg, int number) {
        setMsg(msg);
        setNumber(number);
    }
}

public static void swap(MyObj x, MyObj y)
{
    MyObj tmp = x;
    x = y;
    y = tmp;
}

public static void main(String args[]) {
    MyObj x = new MyObj("Hello world", 1);
    MyObj y = new MyObj("Goodbye Cruel World", -1); 

    swap(x, y);

    System.out.println(x.getMsg() + " -- "+  x.getNumber());
    System.out.println(y.getMsg() + " -- "+  y.getNumber());
}


"Output:
Hello world -- 1
Goodbye Cruel World -- -1"

thus it is clear that Java passes its parameters by value , as the value for pi and everything and the MyObj objects aren't swapped. be aware that "by value" is the only way in java to pass parameters to a method. (for example a language like c++ allows the developer to pass a parameter by reference using ' & ' after the parameter's type)

now the tricky part , or at least the part that will confuse most of the new java developers: (borrowed from javaworld)
Original author: Tony Sintes

public void tricky(Point arg1, Point arg2)
{
    arg1.x = 100;
    arg1.y = 100;
    Point temp = arg1;
    arg1 = arg2;
    arg2 = temp;
}
public static void main(String [] args)
{
    Point pnt1 = new Point(0,0);
    Point pnt2 = new Point(0,0);
    System.out.println("X: " + pnt1.x + " Y: " +pnt1.y); 
    System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
    System.out.println(" ");
    tricky(pnt1,pnt2);
    System.out.println("X: " + pnt1.x + " Y:" + pnt1.y); 
    System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);  
}


"Output
X: 0 Y: 0
X: 0 Y: 0
X: 100 Y: 100
X: 0 Y: 0"

tricky successfully changes the value of pnt1! This would imply that Objects are passed by reference, this is not the case! A correct statement would be: the Object references are passed by value.

more from Tony Sintes:

The method successfully alters the value of pnt1, even though it is passed by value; however, a swap of pnt1 and pnt2 fails! This is the major source of confusion. In the main() method, pnt1 and pnt2 are nothing more than object references. When you pass pnt1 and pnt2 to the tricky() method, Java passes the references by value just like any other parameter. This means the references passed to the method are actually copies of the original references. Figure 1 below shows two references pointing to the same object after Java passes an object to a method.

figure 1 http://www.javaworld.com/javaworld/javaqa/2000-05/images/03-qa-0512-pass2b.gif

Conclusion or a long story short:

  • Java passes it parameters by value
  • "by value" is the only way in java to pass a parameter to a method
  • using methods from the object given as parameter will alter the object as the references point to the original objects. (if that method itself alters some values)
  • useful links:

  • http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
  • http://www.ibm.com/developerworks/java/library/j-passbyval/
  • http://www.ibm.com/developerworks/library/j-praxis/pr1.html
  • http://javadude.com/articles/passbyvalue.htm

  • Here is another article for the c# programming language

    c# passes its arguments by value (by default)

    private void swap(string a, string b) {
      string tmp = a;
      a = b;
      b = tmp;
    }
    

    calling this version of swap will thus have no result:

    string x = "foo";
    string y = "bar";
    swap(x, y);
    
    "output: 
    x: foo
    y: bar"
    

    however, unlike java c# does give the developer the opportunity to pass parameters by reference , this is done by using the 'ref' keyword before the type of the parameter:

    private void swap(ref string a, ref string b) {
      string tmp = a;
      a = b;
      b = tmp;
    } 
    

    this swap will change the value of the referenced parameter:

    string x = "foo";
    string y = "bar";
    swap(x, y);
    
    "output: 
    x: bar
    y: foo"
    

    c# also has a out keyword , and the difference between ref and out is a subtle one. from msdn:

    The caller of a method which takes an out parameter is not required to assign to the variable passed as the out parameter prior to the call; however, the callee is required to assign to the out parameter before returning.

    and

    In contrast ref parameters are considered initially assigned by the callee. As such, the callee is not required to assign to the ref parameter before use. Ref parameters are passed both into and out of a method.

    a small pitfall is, like in java, that objects passed by value can still be changed using their inner methods

    conclusion:

  • c# passes its parameters, by default, by value
  • but when needed parameters can also be passed by reference using the ref keyword
  • inner methods from a parameter passed by value will alter the object (if that method itself alters some values)
  • useful links:

  • http://msdn.microsoft.com/en-us/vcsharp/aa336814.aspx
  • http://www.c-sharpcorner.com/UploadFile/saragana/Willswapwork11162005012542AM/Willswapwork.aspx
  • http://en.csharp-online.net/Value_vs_Reference

  • Python uses pass-by-value, but since all such values are object references, the net effect is something akin to pass-by-reference. However, Python programmers think more about whether an object type is mutable or immutable. Mutable objects can be changed in-place (eg, dictionaries, lists, user-defined objects), whereas immutable objects can't (eg, integers, strings, tuples).

    The following example shows a function that is passed two arguments, an immutable string, and a mutable list.

    >>> def do_something(a, b):
    ...     a = "Red"
    ...     b.append("Blue")
    ... 
    >>> a = "Yellow"
    >>> b = ["Black", "Burgundy"]
    >>> do_something(a, b)
    >>> print a, b
    Yellow ['Black', 'Burgundy', 'Blue']
    

    The line a = "Red" merely creates a local name, a , for the string value "Red" and has no effect on the passed-in argument (which is now hidden, as a must refer to the local name from then on). Assignment is not an in-place operation, regardless of whether the argument is mutable or immutable.

    The b parameter is a reference to a mutable list object, and the .append() method performs an in-place extension of the list, tacking on the new "Blue" string value.

    (Because string objects are immutable, they don't have any methods that support in-place modifications.)

    Once the function returns, the re-assignment of a has had no effect, while the extension of b clearly shows pass-by-reference style call semantics.

    As mentioned before, even if the argument for a is a mutable type, the re-assignment within the function is not an in-place operation, and so there would be no change to the passed argument's value:

    >>> a = ["Purple", "Violet"]
    >>> do_something(a, b)
    >>> print a, b
    ['Purple', 'Violet'] ['Black', 'Burgundy', 'Blue', 'Blue']
    

    If you didn't want your list modified by the called function, you would instead use the immutable tuple type (identified by the parentheses in the literal form, rather than square brackets), which does not support the in-place .append() method:

    >>> a = "Yellow"
    >>> b = ("Black", "Burgundy")
    >>> do_something(a, b)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 3, in do_something
    AttributeError: 'tuple' object has no attribute 'append'
    
    链接地址: http://www.djcxy.com/p/458.html

    上一篇: 在C ++中通过引用传递指针会带来什么好处?

    下一篇: 通过引用传递或通过值传递?