10

If I have this interface:

public interface Foo {
    void bar();
}

Why can't I implement it like this?

public class FooImpl implements Foo {
    @Override
    public Object bar() {
         return new Object();
    }
}

It seems like void should be covariant with everything. Am I missing something?

Edit: I should have been clearer that I'm looking for the design justification, not the technical reason that it won't compile. Are there negative consequences to making void covariant to everything?

MattWallace
  • 1,015
  • 6
  • 12
  • The JLS is pretty clear about that, but maybe someone could provide a technical reason why it may be designed this way. I guess `void` could be a supertype of `Object` with no defined methods. Would make this example work at least. I don't know if it's worth the added complexity. – atamanroman Jan 08 '13 at 16:44
  • @atamanroman Because `void` explicitly means *nothing*; it's a contract stating the method has no return value. Being able to return something would violate that contract--it's just the way it was designed. – Dave Newton Jan 08 '13 at 16:46
  • @DaveNewton there is other no example in the rest of the Java type system of placing an upper bound on a return. What you're saying is an argument against covariant return types in general. "`Object` explicitly means _Object_; it's a contract stating that the method has to return an Object and nothing more". So my question remains - is there a good reason to not consider `void` a supertype of everytype (at least for the purpose of return covariance)? – MattWallace Jan 09 '13 at 00:06
  • @MattWallace How is saying "void explicitly means nothing", which is what it means, anything other than just that?! What you're saying isn't what the JLS says, what I said is. But yes, there is a good reason-to allow the definition of a method that explicitly doesn't return anything. If void was a supertype how would you indicate a method will not ever return something? – Dave Newton Jan 09 '13 at 00:22

8 Answers8

13

void is only covariant with void because the JLS says so:

A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return type R2, if and only if the following conditions hold:

  • If R1 is void then R2 is void.

  • If R1 is a primitive type, then R2 is identical to R1.

  • If R1 is a reference type then:

    • R1 is either a subtype of R2 or R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9), or

    • R1 = |R2|

NPE
  • 486,780
  • 108
  • 951
  • 1,012
5

covariance means that if your methods return type is a Supertype object you can return sub-type Object at runtime, void is not the super type of java.lang.Object(or any Object for that matter except itself as answered by MR NPE)

PermGenError
  • 45,977
  • 8
  • 87
  • 106
2

Technically void cannot be a covariant return type as the caller needs to know the stack layout. Calling a function that returns an object would result of an object-ref on the top of the stack after the INVOKEVIRTUAL/INTERFACE. Void return type leaves nothing on the top of the stack, hence the functions are binary incompatible.

So the JLS rightfully says it's not possible.

bestsss
  • 11,796
  • 3
  • 53
  • 63
1

void effectively means that it returns nothing. You may be getting confused with a void * in C/C++. If you change the interface to be

public interface Foo {
    Object bar();
}

it will work fine because all objects in Java inherit Object.

So, you could do something like this:

public class FooImpl implements Foo {

    @Override
    public Object bar() {
         return new SpecialObject();
    }

}

SpecialObject obj = (SpecialObject) new FooImpl().bar();
Tom Leese
  • 19,309
  • 12
  • 45
  • 70
1

Return types must match for overridden methods.

Foo foo = new FooImpl();
foo.bar();

Unless all implementations comply with the interface and return the same object (or nothing at all) how do I know what that will return?

cowls
  • 24,013
  • 8
  • 48
  • 78
1

void is not part of the java file system.

If we do make it a type, it's more like an empty type, so it should be a subtype of every other type, i.e. it is contra-variant with other types.

In your example, the super class dictates that nothing should be returned, yet the subclass returns something, therefore the subclass violates the superclass's contract.

Object is covariant with other types, if that's what you want.

irreputable
  • 44,725
  • 9
  • 65
  • 93
0

A covariant return type usually means the one that can be replaced by a narrower type. In Java, there is no such relation (supertype-subtype) between void and Object or anything else.

Swapnil
  • 8,201
  • 4
  • 38
  • 57
0

If this were allowed, there would be no way to determine if this should compile or not.

 Foo foo = ...
 Object o = foo.bar(); // is it void or an Object ?
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Of course it wouldn't compile, because you're accessing it through `Foo`. Just like `new FooImpl() { public String bar() { return super.bar(); } };` wouldn't compile even though `return this.bar()` would. – shmosel May 18 '17 at 02:32