Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default generic value

Tags:

generics

scala

Say I have a class:

class SomeClass[+A <: AnyRef, +B <: Any]

To specify it I always have to specify the types of generic parameters too. I.e. to specify its most general version as a method parameter type I have to do def someMethod(param1: SomeClass[AnyRef, Any]) or new SomeClass[AnyRef, Any] to instantiate it. It becomes a major pain when it comes to more complex types which have complex generics.

Is there a way to make the [AnyRef, Any] part implied when I don't provide generic information? For instance def someMethod(param1: SomeClass)?

Is there a way the _ could help me solve this problem and how?

P.S. I apologize for originally not stating the question as clearly.

like image 653
Nikita Volkov Avatar asked Dec 28 '11 18:12

Nikita Volkov


3 Answers

As suggested in my comment, doing something like this can save some typing and is pretty straightforward:

type SomeClassAny = SomeClass[AnyRef, Any]
like image 77
huynhjl Avatar answered Sep 24 '22 22:09

huynhjl


If you don't truly care about what type this thing is going to have, you can parametrize it with [_, _]. Examples might be things like

val thing = new SomeClass[_, _]()

or

def thingDoer(sc: SomeClass[_, _]) { /* Stuff */ }

To be a bit more clear about its nature, the underscore is known as the "existential type", and it's basically the equivalent of a raw type in Java, and it can also function similar to wildcard type from Java. For example, this schizophrenic Java code

public void thingThatTakesAMapList(List<? extends Map> mapList) { /* Whatever */ }

is the same as this Scala code

def thingThatTakesAMapList(mapList: List[_ <: Map[_, _]]) { /* Some incredibly wild subroutine */ }

Also, it's worth noting the distinguishment between List[Any] and List[_] is... very subtle. It is to say that the former is a list of Any, and the latter is a list of [I don't know/care]. _ is quite different from Any, though. For example, if you had a class with this signature

class SillyClass[T <: Map[_, _]]

it would not be valid to do this

val thing = new SillyClass[Any]()

while it could be valid for you to do this

val thing = new SillyClass[HashMap[_, _]]()

and, if a function took a SillyClass as a parameter, you could write

def sillyClassTaker(sc: SillyClass[_])

and be certain that sc was not going be parametrized over type Any; it's parametrized over some unknown subclass of Map[_, _]. That is to say that the underscore is a placeholder, but it still requires that valid type parameters exist in its place. So, while that's all cool and all... I don't particularly recommend using it too much. If you need to do something... wildcard-y, or simply don't care about the type parameters, it's a good option to consider, though.

like image 23
Destin Avatar answered Sep 23 '22 22:09

Destin


How about this?

scala> :paste
// Entering paste mode (ctrl-D to finish)

class SomeClass[+A <: AnyRef]

object SomeClass {
  def apply() = new SomeClass[AnyRef]
}

// Exiting paste mode, now interpreting.

defined class SomeClass
defined module SomeClass

scala> SomeClass()
res47: SomeClass[AnyRef] = SomeClass@4f63b5

Edit:

I think you want something like default arguments, but at the type level. Unfortunately Scala does not have any such feature. You can use type aliases as suggested by @hyhnhjl. That to me seems your best bet.

like image 25
missingfaktor Avatar answered Sep 23 '22 22:09

missingfaktor