Search code examples
javasecuritymethodsparameter-passingobject-initialization

Passing an instance to a method Vs. forwarding parameters


I often encounter situations where I pass instances as parameters to functions. It occurred to me that it is equally possible to forward the parameters of the object instead, and initialize within the method.

Example:

class MyCanvas extends JComponent {

    private static final long serialVersionUID = 1L;

    private static ArrayList<String>    textData;
    private static ArrayList<Rectangle> rectData;

    @Override

    public void paintComponent(Graphics g) {

        if(g instanceof Graphics2D){

            //Draw the rectangles and text
        }
    }

    public void addText(int x, int y, String text){
        textData.add(text);
    }

    //Do this:
    public void addRect(Rectangle rect){
        rectData.add(rect);
    }

    //Or do this?
    public void addRect(int x, int y, int z,  int q){
        rectData.add(new Rectangle(x, y, z, q);
    }

}

Passing four integers, in this case, reduces the variability. Theoretically speaking, the error surface area should be reduced along with the potential for vulnerabilities.

How does the JVM handle these two examples differently?

Is one truly less error/vulnerability prone?

Will one be more efficient than the other in terms of performance?

Note: This is not a question about design preference. There are multiple ways wrap or bind parameters in such a way that either example would be flexible and efficient. All I want to know is what the difference is on the byte code level, and whether or not one is distinctly more efficient/secure at the bytecode level.


Solution

  • From an API design perspective, passing a Rectangle (or a Shape) is better. It supports coding to an interface, not an implementation. In one sense, specifying a corner and dimensions is an implementation; a different implementation would specify opposite corners. By passing a shape, you make your code more adaptable.

    The main problem here is due to the mutability of Rectangle. There are efficiency arguments for this, but I wonder if Shape would be mutable if it were designed today. For many applications, immutable data types provide many benefits, and safer sharing of data is one of them.

    Since you are implementing MyCanvas, you can satisfy yourself that the Rectangle instance is not modified, and is therefore "secure." However, if someone else is writing the caller, and MyCanvas is a black box they can't fully trust, there are two things that can help.

    First, you can document the MyCanvas methods that accept a shape, specifying that the shapes are not modified. In Java, this specification should be placed in Javadoc comments on methods and classes. This is a common practice; unless you are writing a plugin system that might execute agents that are written by untrustworthy authors, programmers typically rely on this commitment, or contract, in an API.

    Second, if the caller doesn't have that assurance, they can copy "their" Rectangle instance to a temporary copy, and pass you the copy. Because they never read the state of the Rectangle after the method returns, it doesn't matter what you do to it. Because Rectangle is mutable, this can be done fairly efficiently.


    From a byte code perspective, passing the Rectangle is faster. An separate instruction is executed for each parameter that is passed. More parameters, more instructions. Also, passing the Rectangle allows the caller's instance to be re-used, while passing primitive elements requires allocation of a new Rectangle that might be unnecessary.

    I don't know what you talking about when you say, "Passing four integers, in this case, reduces the variability. Theoretically speaking, the error surface area should be reduced along with the potential for vulnerabilities."

    I do know that in the real, practical world, methods with multiple arguments of the same type, like four int parameters, are extremely error-prone. Naming them nonsense like q and z makes that problem even worse. Taking advantage of strong typing for parameters makes your program safer by eliminating bugs at compile-time.