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.
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.