Nikita Volkov
Nikita Volkov

Reputation: 43309

Default generic value

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.

Upvotes: 6

Views: 801

Answers (4)

huynhjl
huynhjl

Reputation: 41646

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

type SomeClassAny = SomeClass[AnyRef, Any]

Upvotes: 7

Destin
Destin

Reputation: 1214

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.

Upvotes: 5

missingfaktor
missingfaktor

Reputation: 92026

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.

Upvotes: 3

Kim Stebel
Kim Stebel

Reputation: 42037

Usually it can be inferred from the types of constructor parameters, but if the constructor doesn't take any parameters, you have to specify the type explicitly. Of course, as missingfaktor pointed out, you can always write a method for that to save you some typing.

Upvotes: 1

Related Questions