gaosan80
gaosan80

Reputation: 111

Writing a method to return a java Class constrained to a certain type in Scala

For example, I have this:

abstract class Vehicle

class Car extends Vehicle

And I want to write a method that returns a java Class, but constrained to only Classes of type Vehicle.

object CarDealer {
  def getVehicularClass: Class[Vehicle] = classOf[Car]
}

I am not able to get the following different approaches to work:

  1. The way I would normally deal with this

    object CarDealer {
      def getVehicularClass[A <: Vehicle]: Class[A] = classOf[Car]
    }
    
    [error]  found   : java.lang.Class[Car](classOf[Car])
    [error]  required: Class[A]
    [error]   def getVehicularClass[A <: Vehicle]: Class[A] = classOf[Car]
    
  2. Using an abstract type

    type V <: Vehicle
    
  3. Using an implicit manifest (seems like it only constrains method arguments and not return values)

Can anyone help?

Thanks!

Upvotes: 1

Views: 223

Answers (3)

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297165

This constrain is adequately expressed with existential types:

object CarDealer {
  def getVehicularClass: Class[_ <: Vehicle] = classOf[Car]
}

Of course, there might be other requirements that make an existential type inappropriate, but your problem is not particularly well stated.

Upvotes: 0

paradigmatic
paradigmatic

Reputation: 40461

The type Class[T] is invariant in type T. Thus even if A extends B, classOf[A] is not a subtype of classOf[B]. Therefore there's no exact solution to your problem...

Upvotes: 0

Rex Kerr
Rex Kerr

Reputation: 167891

Vehicle is the supertype. You don't know that some subtype A of Vehicle is going to include Car, so you can't write it generically that way. What if someone asked for a Bus? The CarDealer can't help, but the type signature promises that it can make it work for any A <: Vehicle that you ask for.

If you don't care about preserving the real type of the vehicle, just write

object CarDealer {
  def getVehicularClass: Class[Vehicle] = classOf[Car]
}

Alternatively, if you want some interface obeyed, you specify in the interface what you want:

trait VehicleClass[A <: Vehicle] {
  def getVehicularClass: Class[A]
}

and then you have your object state which subclass of vehicle it is promising to return:

object CarDealer extends VehicleClass[Car] {
  def getVehicularClass = classOf[Car]
}

and now all promises are specified and lived up to.

Upvotes: 1

Related Questions