What Is a Covariant Return Type

What is a covariant return type?

Covariant return, means that when one overrides a method, the return type of the overriding method is allowed to be a subtype of the overridden method's return type.

To clarify this with an example, a common case is Object.clone() - which is declared to return a type of Object. You could override this in your own class as follows:

public class MyFoo
{

...

// Note covariant return here, method does not just return Object
public MyFoo clone()
{
// Implementation
}
}

The benefit here is that any method which holds an explicit reference to a MyFoo object will be able to invoke clone() and know (without casting) that the return value is an instance of MyFoo. Without covariant return types, the overridden method in MyFoo would have to be declared to return Object - and so calling code would have to explicitly downcast the result of the method call (even thought both sides "know" it can only ever be an instance of MyFoo).

Note that there's nothing special about clone() and that any overridden method can have a covariant return - I used it as an example here as it's a standard method where this is often useful.

Covariant return type in Java

Yes.

In early java that was not the case, but it was changed in Java 5.0.

You cannot have two methods in the same class with signatures that only differ by return type. Until the J2SE 5.0 release, it was also true that a class could not override the return type of the methods it inherits from a superclass. In this tip you will learn about a new feature in J2SE 5.0 that allows covariant return types. What this means is that a method in a subclass may return an object whose type is a subclass of the type returned by the method with the same signature in the superclass. This feature removes the need for excessive type checking and casting.

The source of this information is no longer available on the interwebs.

Covariant data types: Why return type must be same as or child of its 'parent method' return type?

The way to understand this is to think of the subclass as a specific type of the parent class. This means it still needs to adhere to the behavior defined by the parent. The parent class defines a someMethod method that returns an Object. Subclasses can't break this behavior, but they can further specify it - a DogHouse's someMethod still returns an Object, it just happens to be a String.

c# 9.0 covariant return types and interfaces

Whilst covariant return types in interfaces are not supported as of C# 9, there is a simple workaround:

    interface A {
object Method1();
}

class B : A {
public string Method1() => throw new NotImplementedException();
object A.Method1() => Method1();
}

Covariant return type best practices

The return type must strike a balance between the needs of the caller and the needs of the implementation: the more you tell a caller about the return type, the harder it is to change that type later.

Which is more important will depend on the specific circumstances. Do you ever see this type changing? How valuable is knowing the type for the caller?

In the case of IntegerGetter.get(), it would be very surprising if the return type ever changes, so telling the caller does no harm.

In the case of IntegerGetter.getAll(), it depends on what the caller uses the method for:

  • If he merely wants to iterate, an Iterable would be the right choice.
  • If we need more methods such as size, Collection might.
  • If he relies on the numbers being unique, a Set.
  • If he additionally relies on the numbers being sorted, a SortedSet.
  • And if it actually needs to be the red black tree from the JDK so it can manipulate its internal state directly for an ugly hack, a TreeSet might be the right choice.

Strategy Pattern and Covariant Return Type in C++

This is a perennial problem. The core issue is, Context wants to have dynamic control of its strategy (including the dynamic type of its return value) but its users want static assurances on that return value. You can template Context on the strategy and/or on the return type, and potentially template Strategy on the return type, but fundamentally you’ll need to introduce the limits on the return type at compile time or you’ll need unsafe casting at runtime.

How to use covariant return types with lists in interface methods?

This does not compile.

You have two options:

  • Try List<? extends Player> getPlayers() in your interface, and now you can write List<EspnPlayer> getPlayers() which is a valid implementation if this. Note that it is not possible to call .add() on this list, for proper reasons (after all, adding a non-EspnPlayer to this list would break the list!)
  • If that add thing is required, then there's no way out except to have:
interface NbaService<T extends Player> {
public List<T> getPlayers();
}


In Object Oriented Programming, "programming to an interface" is often considered a best practice.

Nice use of the passive voice there, but, as wikipedia editors would say, [citation needed].

There is a grain of truth to this, but as with all programming style suggestions, it's oversimplified. Which isn't a problem, but that's why the following maxim is pretty much always true: If you don't understand the reasons behind a style recommendation, then blindly following it is stupid and will result in worse code. There is no easy out: You must first grok the considerations underlying the recommendation, and until then you just cannot use the recommendation.

Covariant return type implementation

If you're just curious, for example you can use Shapeless

import shapeless.{Generic, HNil}

def get[U <: Animal]()(implicit generic: Generic.Aux[U, HNil]): U =
generic.from(HNil)

get[Dog] // Dog() for case class, Dog@34340fab otherwise
get[Cat] // Cat() for case class, Cat@2aafb23c otherwise
get[Nothing] // doesn't compile
get[Null] // doesn't compile
get[Cat with Dog] // doesn't compile

Or you can use a macro

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

def get[U <: Animal](): U = macro getImpl[U]

def getImpl[U: c.WeakTypeTag](c: blackbox.Context)(): c.Tree = {
import c.universe._
q"new ${weakTypeOf[U]}"
}

Or you can use runtime reflection

import scala.reflect.runtime.universe._
import scala.reflect.runtime

def get[U <: Animal : TypeTag](): U = {
val typ = typeOf[U]
val constructorSymbol = typ.decl(termNames.CONSTRUCTOR).asMethod
val runtimeMirror = runtime.currentMirror
val classSymbol = typ.typeSymbol.asClass
val classMirror = runtimeMirror.reflectClass(classSymbol)
val constructorMirror = classMirror.reflectConstructor(constructorSymbol)
constructorMirror().asInstanceOf[U]
}

(see also example with Java reflection in @KrzysztofAtłasik's answer.)

Or you just can introduce a type class and define its instances manually

trait Get[U <: Animal] {
def get(): U
}
object Get {
implicit val dog: Get[Dog] = () => new Dog
implicit val cat: Get[Cat] = () => new Cat
}

def get[U <: Animal]()(implicit g: Get[U]): U = g.get()


Related Topics



Leave a reply



Submit