-1

Let's say you have a class of object with three integer fields that you want to possibly change, all in the same way, with one method.

Let's keep it simple and say all that the method does is add 1 to the parameter passed to it.

That is to say, the desired behavior is that by the time the method has completed, the relevant field has increased by 1.

This is impossible to achieve in Java using the primitive type "int" for those fields.
I know about how Java is "always" pass by value, and not pass by reference, - and - i've heard whisperings on the internet that this is one reason that the Integer class exists, along with other object "wrapper" classes for ordinarily primitive types such as int and double.

Sending an object as an argument to a method should, in theory, provide a way to [effectively, if not technically] pass by reference, since the value that is passed, is supposedly the value of the reference to the object. Very tricky. BUT - and this is where my annoyance comes in - I've tried achieving this very simple task by passing an Integer argument instead of an int, and the desired behavior was still not accomplished. 1 was not added to the relevant field.

And yet, when I made my very own object, which consisted of just one field, an int value, and passed an instance of this object as an argument to an appropriate method which would simply add 1 to the passed parameter, the desired behavior was in fact accomplished. 1 was added to the relevant field.

So the questions orbiting around this query are - Is it really going to be necessary to craft my own homemade class just to carry a simple integer value every time I want to achieve this desired behavior? Can the existing tool provided by Java, Integer, really not perform this simple task?

Instead of having one nice, neat method to handle all three of the hypothetical integer fields i mentioned in the beginning, I felt compelled (in a separate, similar project that ultimately provoked this line of thinking) to make a separate method corresponding to each of the three fields, with essentially the same exact code in each one. This seems very inefficient.

It may not seem like a big deal, on the surface, to write three similar methods instead of one, but to clarify why this dismays me - imagine instead of an object with three integer fields as I stated, there are say, i don't know, four thousand. It would be so much better to write just one thing to perform the same kind of behavior, instead of copying and pasting (and changing whatever little bits necessary) four thousand times.

So I suppose the ultimate question is, Why doesn't Integer function in a reasonable way? What's the point of wrapping a primitive in an Object at all, if it doesn't even help perform something this simple? Am I missing something simple about how to get Integer to function in the desired way? (Hopefully so) The answer seems close yet infuriatingly out of reach since "RInteger" produces the desired behavior, yet "Integer" doesn't.

The entire source code I used while trying to figure out how to construct this painstaking question is below.

package r9mp;

import javax.swing.SwingUtilities;

public class RefTest2 {
//[main m]
public static void main(String[] args){
    SwingUtilities.invokeLater(new Runnable(){
        public void run(){
            new RefTest2();
        }
    });
}
//[fields]
int i;
Integer I;
RInteger RI;

//[constr]
public RefTest2(){
    intTest();
    IntegerTest();
    RIntegerTest();

    display();
}

//[methods]
private void intTest(){
    i = 100;
    intMethod(i);
}
private void IntegerTest(){
    I = 100;  //boxing? auto?
    IntegerMethod(I);
    I = 100; //just in case.
    IntegerMethod2(I);
}
private void RIntegerTest(){
    RI = new RInteger(100);
    RIntegerMethod(RI);
}

private void intMethod(int ipar){
    ipar = ipar + 1;//no change. expected.
}
private void IntegerMethod(Integer IPar){
    IPar = IPar + 1;//no change. frustrating.
    pln("From inside IntegerMethod: IPar = " + IPar );
    pln("From inside IntegerMethod: I = " + I );
}
private void IntegerMethod2(Integer IPar){
    IPar = new Integer(IPar+1);//still no change.  there are no set methods for Integer, or I'd try them.
}
private void RIntegerMethod(RInteger riPar){
    riPar.value = riPar.value + 1;
}

private void display(){
    pln(
            "Display...    \n" +
            "i: "  + i  + "\n" +
            "I: "  + I  + "\n" +
            "RI: " + RI + "\n" +
            "--------"
            );
}

private void pln(){
    pln("");
}
private void pln(String s){
    System.out.println(s);
}

//[internal class]
private class RInteger{
    int value;
    public RInteger(int v){
        value = v;
    }
    public String toString(){
        return ""+value;

    }
}

}

And, here is the output...RefTest2 output

Ryan McNames
  • 497
  • 4
  • 3
  • Hi Ryan, you seem to be using your Java class `RefTest2` in a strange way. Typically, the class would have fields which get updated. So it doesn't really matter if setter method variables are pass by reference or pass by value, because we only use them as read-only fields for passing around information. – Tim Biegeleisen Jan 28 '17 at 12:49
  • 1
    If you want to write a method with side effects (which is already pretty bad), then use an array. Quite obvious workaround. – Tom Jan 28 '17 at 12:49
  • 1
    Since `Integer` is immutable it basically behaves the same way as `int` does in terms of passing it to methods and changing it. You cannot change the value inside the `Integer`, you can only create new instance which then overrides the passed value and leaves the previous reference in tact. – luk2302 Jan 28 '17 at 12:49
  • You write to the fields, but you never actually read from them. Is that intentional? It's not clear to me what you're expecting to have happen. – yshavit Jan 28 '17 at 13:15
  • Maybe your "desired" behaviour for Integer isn't desired by a lot of people? Or is actively undesirable for many people? – Erwin Bolwidt Jan 28 '17 at 14:01

2 Answers2

1

First of all, you need to read up on immutability to find out why it is a very good thing to have. There even exist entire languages (functional, mostly) that capitalize on it.

Once you have read about that, then read Eric Lippert's series of articles on immutability. Start here: https://blogs.msdn.microsoft.com/ericlippert/2007/11/13/immutability-in-c-part-one-kinds-of-immutability/ Mind = blown.

But to give you a quick hint as to why primitive wrappers like Integer are immutable, let me just say that these classes are often used as keys in Hash Maps, and a key must be immutable, so that its hashCode will never change, otherwise the hash map will fail with very difficult to track down behaviour. Mutable keys in hashmaps are nasty bugs.

You can achieve what you want with a class of your own devise which plays the role of a reference, or by simply passing an array and modifying the element at array[0].

My personal preferences are as follows:

  • I would try to do as much as possible with return values.
  • When return values are inapplicable, (as the case is with invokeLater,) then inner/nested/anonymous classes that have access to the fields of the enclosing class are my next preference.
  • When that's not an option either, then special classes crafted precisely for the application at hand are my next option. (MyMutableNumberWrapper.)
  • And when I just want something quick and dirty, then general-purpose classes like Ref<T> (or even single-element arrays) would be my final option.
Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • I was aware that an array would achieve the desired behavior as well.. in fact that was part of what I tested in RefTest, but I didn't include it in RefTest2. I'm somewhat reluctant to use arrays, just for the fact that it's slightly more of a confusing tangle to look at. If user made objects are what it really takes, to achieve this kind of thing, then I suppose that's what I'll end up doing. As for hash maps, or maps in Java at all, i'm aware of them, but i've done nearly no experimenting with them, yet. – Ryan McNames Jan 28 '17 at 13:13
  • I agree, arrays are a clunky and hacky solution to the problem. I amended my answer with a bit more information. – Mike Nakis Jan 28 '17 at 13:22
  • 1
    I am pretty sure that there is big misleading in phrase "Java always passes arguments by value". It is correct for primitives, but for objects Java always passes object reference as argument. Object it-self is not. To make it consistent with primitives their wrappers are immutable and it allows to have code as 'Integer a = 100;' working instead of 'Integer a = new Integer(100);` – Vadim Jan 28 '17 at 13:35
  • @Vadim oh yes, I could not agree more. See this previous answer of mine: http://softwareengineering.stackexchange.com/a/286013/41811 – Mike Nakis Jan 28 '17 at 13:45
  • @MikeNakis I wondered as I posted my code whether the 'invokeLater' bit in the main method would alter desired behavior, somehow... I've been getting used to writing it that way, since I've been playing around with making simple user interfaces with swing elements.. JFrames and JPanels and the like. I feel like if it were the case that this modified the output, it would be a daunting task to figure out exactly why. I am vaguely aware of anonymous classes, but i would not have guessed they'd be applicable, nor have I tried using them. The Ref suggestion is interesting. – Ryan McNames Jan 28 '17 at 13:45
  • @Mike Nakis - Yep, long time ago I put in my mind simple thing - "there is no pointer conception in Java, because in Java anything is a pointer"... with little exclusion for primitives. And I do not think about it anymore. :-) – Vadim Jan 28 '17 at 13:48
1

How about one method for primitives and their wrappers?

private int incInteger(int value)
{
    return value + 1;       
}

and call for it:

int intVal = 100;
intVal = incInteger(intVal);

Integer integerVal = 200;
integerVal = incInteger(integerVal);
Vadim
  • 4,027
  • 2
  • 10
  • 26
  • this might be what ends up being the best answer... at least, if i could be certain that it would be the best way to do things in all or most cases. Instead of performing the entire thing separately in the method, your solution puts the actual value-setting part outside of it, with the 'intVal =' and 'integerVal ='. If this kind of thing does turn out to be the best / only solution, then I will have to make an effort to pound it into my brain to code this way, to avoid giving myself little other option than to write tons of nearly identical methods... – Ryan McNames Jan 28 '17 at 13:32
  • 1
    It is good for primitives. For other classes it is a bad idea to replace object with new instance inside the method. If it is needed it must be done in caller code. Of course Inside the method properties of passed object can be changed. That is a common practice. Also everywhere there are tons of such things like "Holder" with Object value in it passed when it is required. Your RInteger class is a "Holder". But it is not needed for primitives. – Vadim Jan 28 '17 at 13:44