0

From this book:

Find the kth to last element of a singly linked list. One of the proposed solutions is as follows:

  public class IntWrapper{
    public int value = 0;
  }

  Node nthToLast3(Node head, int k, IntWrapper i){
    if (head == null){
      return null;
    }
    Node node = nthToLast3(head.next, k, i);
    i.value = i.value + 1;
    if (i.value == k){
      return head;
    }
    return node;
  }

Why do we have to create the int Wrapper class and can't we use an int directly?

bigTree
  • 2,103
  • 6
  • 29
  • 45
  • 1
    @GriffeyDog Actually, it's not. Nowhere near. He's asking why you have to create a wrapper, while the question you linked is asking if Java is pass-by-reference or pass-by-value. While they are related, they are nothing like duplicates. – Nic Dec 22 '14 at 22:20
  • 1
    It is not clear in this code what the wrapper wants to do. Actually it looks more like a job for field. However, if you want to return more than one value (something you would do with modifying an out variable) you basically have the option to return a result (tupel) object `class NodeAndPosition { int pos; Node node; }` or modify one of the referenced objects. – eckes Dec 22 '14 at 22:22
  • Couldn't you use `Integer`, which is a built-in wrapper for `int`? – mbomb007 Dec 22 '14 at 22:57
  • 2
    @mbomb007 `Integer` is immutable. You can't use it as a holder. – Sotirios Delimanolis Dec 22 '14 at 23:02
  • @newbiedoodle You have to have the wrapper... because Java is pass-by-value. – chrylis -cautiouslyoptimistic- Dec 22 '14 at 23:55
  • 1
    FYI, sometimes I work around this by creating a one-element array instead of declaring a new class. Thus `Node nthToLast3(Node head, int k, int[] i)` ... `i[0] = i[0] + 1;` It's a bit ugly, so I try not to do this for production code. I prefer the wrapper class. However, I believe Android uses this kind of thing in its API. – ajb Dec 23 '14 at 00:12
  • @chrylis ...Yes? What about it? – Nic Dec 23 '14 at 13:03

4 Answers4

3

What this trick does, is to wrap an int (native type) in an object (Object derived type). Everything is passed by value in Java, and for objects, the value of the reference is passed as an argument, in a sense (think of it like a pointer value in C/C++, for example).

Nick Louloudakis
  • 5,856
  • 4
  • 41
  • 54
  • So, since objects are passed by value as well, then I still don't understand why the value would be updated? (I don't get the analogy with c pointers) – bigTree Dec 22 '14 at 22:42
  • Objects are not passed by value. Object references are passed by value. It is like saying you are passing the value of an object pointer, at least this is what I think of it. – Nick Louloudakis Dec 22 '14 at 22:50
2

The author uses IntWrapper instead of an int because he wants to achieve persistent state for a value between the callers and callees.

A modification to the int member of an IntWrapper instance in a callee will be visible to a caller.

With a plain int, that's not possible because it's a primitive type, and hence it will be passed by value (it will be 'copied' if I may).

user123
  • 8,970
  • 2
  • 31
  • 52
2

It is impossible in Java to pass primitive values by reference. This is a restriction on the language itself.

Technically, the only things you can pass into methods are "primitives, and pointers to objects". The latter also being a form of primitive. Java possesses neither references nor const object passing.

Daniel
  • 4,481
  • 14
  • 34
-1

The point is that you want to be able to set the value of i.

ints are in Java implemented as primitive data, they are passed-by-value. This means that the following code doesn't set a:

public void Foo () {
    int a = 5;
    System.out.println(a);//prints 5
    setA(a);
    System.out.println(a);//prints 5
}

public void setA (int a) {
    a = 3;
}

Java copies the value of the variable on the stack and the copy is modified leaving the original a untouched.

By using a Wrapper, you store the int in an object. Since objects are passed-by-value from a "variable perspective", or passed-by-reference from the objects perspective, you refer to an object that contains an int. In other words, aw referers to the same instance. Because you copied the reference an not the object. Changes made by the callee are thus reflected in the view of the caller.

public void Foo () {
    IntWrapper aw = new IntWrapper();
    aw.value = 5;
    System.out.println(aw.value);//prints 5
    setA(aw);
    System.out.println(aw.value);//prints 3
}

public void setA (IntWrapper aw) {
    aw.value = 3;
}

This is a useful hack in Java when you want to return multiple values or modify a variable of the caller.

C# alternatively provides the ref keyword, that enable call-by-reference for primitive values.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • 3
    Probably because of the "pass by reference" claim. – Keppil Dec 22 '14 at 22:24
  • @Keppil: Well `object`s are passed by reference... Do you have a counterexample? – Willem Van Onsem Dec 22 '14 at 22:26
  • <- just the messenger. No shooting please. – Keppil Dec 22 '14 at 22:26
  • @Keppil, sure but as far as I know, the claim is correct, I don't see why this raises issues... :s – Willem Van Onsem Dec 22 '14 at 22:27
  • 5
    Java does not support pass by reference. Object references are passed by value, which is completely different. Pass by reference means that you can write a swap method that swaps two objects. This is completely impossible in Java. – Paul Boddington Dec 22 '14 at 22:28
  • 1
    There is no call-by-reference in Java. – Fabian Barney Dec 22 '14 at 22:29
  • @pbabcdefp: no, pass by reference doesn't imply you have any tools to **modify** the reference. That would by *pass-by-pointer*. There is a clear difference between a reference and a pointer. It depends on how you see an `object`. If you see an object only as the *reference* to that object, it is indeed, pass-by-value. But if you see objects as the objects themselves, it is pass-by-value. – Willem Van Onsem Dec 22 '14 at 22:30
  • That is why safest way to say it is that Java is *pass-by-value-of-reference*. – Pshemo Dec 22 '14 at 22:31
  • related: http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value – Ian McLaird Dec 22 '14 at 22:31
  • @IanMcLaird: Yeah, I read that article, as specified in the previous comment, it depends on how you see an `object`. If you see an `object` **only** as the reference to that object, it is indeed pass-by-value, otherwise if you see an `object` as the object itself, it is pass-by-reference. Apperently `C#` sees it as pass-by-reference, since otherwise the `ref` keyword should be badly designed. – Willem Van Onsem Dec 22 '14 at 22:33
  • Passing by reference doesn't apply to objects, it applies to variables. [My own answer](http://stackoverflow.com/a/24546764/438154) to that question explains this (as well as the actual thing that is passed in Java). Although, I understand what you are trying to express in your answer, the parts concerning passing by reference are wrong. – Sotirios Delimanolis Dec 22 '14 at 22:41
  • @SotiriosDelimanolis: well I slightly softened the claim. But it realy depends on how you see an object. If you read *Modern Compiler Implementation*, it is clear that terms are sloppy defined. Literally it is true it is passed-by-value, but it really conflicts with almost any introduction course on Java where objects are represented as real objects... – Willem Van Onsem Dec 22 '14 at 22:44
  • The `ref` keyword in C# allows true pass by reference. You can do this in C#: `public static void Swap(ref string a, ref string b) { string temp = a; a = b; b = temp; }`. Then the caller can do this: `string x = "X", y = "Y"; Swap(ref x, ref y); Console.WriteLine(x);` and the output is `Y`. This is completely impossible in Java. – Paul Boddington Dec 22 '14 at 22:57
  • @pbabcdefp: well I mentioned this in the end of the answer. And softened the claim about call-by-reference in the Java part... As mentioned before, it depends on whether the perspective is the variable or the object. And for `strings` what you say holds, but not for `int`'s, you do a value swap, not a reference swap. A reference swap would imply that your `references` point to something different. You load different values in the variables that happen to be each others... That's something different... In both C#/Java, `string`s are objects after all, so double reference... – Willem Van Onsem Dec 22 '14 at 23:07
  • It does hold for `ints`. Try it. `public static void Swap(ref int a, ref int b) { int temp = a; a = b; b = temp; }`. Then use the method: `int x = 1, y = 2; Swap(ref x, ref y); Console.WriteLine(x);` and the output is 2. Again, completely impossible in Java. – Paul Boddington Dec 22 '14 at 23:10
  • @pbabcdefp: if you had read the comment more carefully, you would see that the comment specified that you do a *swap-by-value* and not a *swap-by-reference*. This means that when you leave the `swap` function, `x` doesn't refer to what `y` was originally refering and vice versa. This can have serious concequences in the event of cascading call-by-reference calls. But also makes it clear how completely schizophrenic these concepts actually are... – Willem Van Onsem Dec 22 '14 at 23:16