tags:

views:

199

answers:

6

(I thought I once read something about this in a book, but now I'm not sure where to find it. If this question reminds you of some material that you've read, please post a reference!)

What are the pros and the cons of primitives in interfaces?

In other words, is one of these preferable to the other and why? Perhaps one is preferable to the other in certain contexts?

public interface Foo {
    int getBar();
}

or

public interface Foo {
    Integer getBar();
}

Similarly:

public interface Boz {
    void someOperation(int parameter);
}

or

public interface Boz {
    void someOperation(Integer parameter);
}

Obviously there's the issue of having to deal with nulls in the non-primitive case, but are there deeper concerns?

+6  A: 

Primitive types should be used for efficiency and simplicity unless there is a specific reason to use the object type (e.g. need null). Using the object types can lead to various subtle errors e.g. null, mistakenly comparing if two references are to the same object instead of the same value, etc. Observe how Java's own libraries use the primitive types except for containers that take Objects.

Arkku
+2  A: 

I would say that for the primitives, there is usually little reason to use the primitive wrapper as a return type. One argument is simply the memory requirements. With a primitive return value you only need the X bytes for the return value vs the wrapper where you have the object overhead. The only place where you might save is the cached value for things such as Integer.valueOf(1), but for example with integer this only works for values -128 -> 127.

While lexicore does make a valid point with using null as a special case return value, there are many times where you can do the same with the primitve value (such as something in the API that says "Integer.MIN_VALUE is returned when the result can not be caluclated". Which is viable in many cases for all of the primitives except boolean.

There is also always the option of exceptions as one could argue that an interface should always be well defined for all possible inputs and that an input that would cause a return value to be undetermined is the definition of an exceptional case (and as such perhaps a good case for an IllegalArgumentException).

A final (adimittedly much less elegeant) solution is to add some sort of state checking method to the interface that can be tested after a call to the method that may not execute as desired:

boolean b = (interface).doFoo();
if((interface).wasError()){
  //doFoo did not complete normally
}else{
  //do something fooish
}

where wasError can clear itself automatically in the style of Thread's interrupt flag (note that this approach will be error prone in multi threaded code).

M. Jessup
You don't need the parentheses around interface.
Steve Kuo
The parens are there as a place holder i.e. [name_of_your_interface_here].doFoo(), not meant as language syntax
M. Jessup
A: 

Yes , The major use you can see is , when you transfer the object over network. ** The use of serialization. **

srinannapa
+1  A: 

Except for the rare cases where primitives are troublesome (I've had some "nice" experience with CORBA), I'd suggest using primitives.

Bozho
Can you please elaborate a bit? Maybe an example?
Greg Mattes
well, when I was using RMI, primitives as method arguments were not passed correctly (resulted in weird exceptions), so I had to use wrappers. Might be version-specific, I don't know.
Bozho
Sorry but that's quite impossible for me to believe. I've been using RMI for 13 years and never seen that. You must have have bugs in your code.
EJP
I wish it has been the case, but the exceptions were in the deserialization mechanism - nowhere near my code ;)
Bozho
RMI really doesn't have this problem. It must have been *application*-specific. Did you have custom writeObject() or readObject() or readResolve() or writeReplace() or readExternal() or writeExternal() methods?
EJP
nope. sorry, I can't recall more details. It was 2 years ago :)
Bozho
@EJP - now I think it really wasn't RMI but CORBA that caused the troubles. Thanks for paying attention to this.
Bozho
A: 

I'm thinking of stuff like this too:

Suppose that we have this type:

public interface Foo {
    int getID();
}

Then, for whatever reason, an ID type is introduced:

public interface Foo {
    FooID getID();
}

Now, suppose that some client was written before the change, and the client contains code like this:

if (A.getID() == B.getID()) {
    someBehavior();
}

Where A and B are Foos.

This code would be broken after the change because the primitive equality comparison (==) between the ints, which was ok before the change, is now incorrectly comparing reference values rather than invoking equals(Object) on the identifiers.

Had getID() produced an Integer from the start, the correct client code would have been (ok, the correct client code might have been this. Boxing conversions would have been applied with == so that would have worked too):

if (A.getID().equals(B.getID())) {
    someBehavior();
}

Which is still correct after the software evolved.

Had the change been "the reverse," in other words, had getID() originally produced some FooID type, then had it been changed to produce int, the compiler would have complained about calling equals(Object) on a primitive and the client code would have been corrected.

There seems to be some feeling of "future proofing" with the non-primitive type. Agree? Disagree?

Greg Mattes
Why not use FooID now and hide the implementation details from the user? The readability of the code will improve and possible refactoring is simplified (e.g. if you would like to change to BarID later on).
matsev
In my opinion this "future proofing" is nowhere near worth the sacrifice in simplicity, legibility or efficiency (both storage and performance). The example given here also seems unrealistic in assuming the use of `equals` would make different object types compatible. In the general case it would not be a reasonable assumption that every user of that interface has used the object only in a manner that would be compatible with the new type.It would be better to design such compatibility by including e.g. `boolean idEquals(Foo)`. Changing types in existing methods is inherently incompatible.
Arkku
@matsev I think you're touching on my point. With an object type, the implementation details, `int`, `long`, or something more complex, are hidden and can be changed more easily. And calling `equals()` makes sense and will continue to make sense when changes occur.
Greg Mattes
@Arkku I'm not sure that I agree that calling `equals()` is significantly less readable, but that's a matter of taste I suppose. It is slightly more verbose, but only slightly. The efficiency stuff can only be tested by profiling, so that's a case-by-case thing. Not sure I'm following how equals would fail in the presence of different FooID implementations, each implementation could check whether the comparison is happening on an object of the same type with `instanceof` and produce `false` if not.
Greg Mattes
If you are using the object wrapper types (`Integer` etc), they are never going to be more efficient than using the wrapped primitive type directly. Even the best optimisation would just reduce it to the primitive type. As for `equals`, I didn't mean that `equals` would fail, but rather that just having the same syntax for `FooId.equals()` and `BarId.equals()` doesn't mean that you can, in the general case, change `FooId` to `BarId` in an existing interface and assume no-one has used some *other* features of `FooId` that make the change incompatible with `BarId`.
Arkku
And if the only significance of the values returned by `getId` is to allow comparing ids, one could instead encapsulate the id type altogether and provide a method for the comparison. Or, if the values of ids do have a some external significance/meaning on their own, the data type should be chosen to reflect that meaning. It cannot be changed later as users of the interface might have done any number of things depending on the exact type (even the exact class name). If the values are best represented by a custom class, by all means create one, but then "future proofing" is not the reason.
Arkku
@Arkku Oh, sure, I see what you're saying about other features. Certainly there could be other changes that are needed. Can't just swap out one type for another expect everything to be ok in all cases - yep. My point was that having the object instead of the primitive might make for less changes, in particular for equality comparison (maybe a better example would help). Less changes; less chances for bugs perhaps. I also see what you're saying about the object efficiency relative to the primitive efficiency, but again, there's the issue of whether that difference is a bottleneck in the system.
Greg Mattes
A: 

Use primitives. Auto-boxing/-unboxing will cast your ints to Integers and so on. Primitives are also allocated on the stack, not the heap. By using wrapper classes you are using more memory and incurring more overhead; why would you want to do that?

Beau Martínez