tags:

views:

80

answers:

2

Hello,

I'd like to write a type alias to shorten, nice and encapsulated Scala code. Suppose I got some collection which has the property of being a list of maps, the value of which are tuples. My type would write something like List[Map[Int, (String, String)]], or anything more generic as my application allows it. I could imagine having a supertype asking for a Seq[MapLike[Int, Any]] or whatever floats my boat, with concrete subclasses being more specific.

I'd then want to write an alias for this long type.

class ConcreteClass {
  type DataType = List[Map[Int, (String, String)]]
  ...
}

I would then happily use ConcreteClass#DataType everywhere I can take one, and use it.

Now suppose I add a function

def foo(a : DataType) { ... }

And I want to call it from outside with an empty list. I can call foo(List()), but when I want to change my underlying type to be another type of Seq, I'll have to come back and change this code too. Besides, it's not very explicit this empty list is intended as a DataType. And the companion object does not have the associated List methods, so I can't call DataType(), or DataType.empty. It's gonna be even more annoying when I need non-empty lists since I'll have to write out a significant part of this long type.

Is there any way I can ask Scala to understand my type as the same thing, including companion object with its creator methods, in the interest of shortening code and blackboxing it ? Or, any reason why I should not be doing this in the first place ?

+2  A: 

What about this?

class ConcreteClass {
  type DataType = List[String]
}
object DataType {
  def apply(): ConcreteClass#DataType = Nil
}
//...
val a = DataType()

Oleg Galako
This works. Thanks. However with this I have to define every single method of List to do what I want, and it's a little verbose. It's very good to have control over what can be called too. Thanks to your answer I think I got the generic solution for the "may call all List methods": posting it now. Thanks a lot :)
Jean
+2  A: 

The answer was actually quite simple:

class ConcreteClass {
  type DataType = List[String]
}
object ConcreteClass {
  val DataType = List
}
val d = ConcreteClass.DataType.empty

This enables my code to call ConcreteClass.DataType to construct lists with all the methods in List and little effort.

Thanks a lot to Oleg for the insight. His answer is also best in case you want not to delegate to List any call to ConcreteClass.DataType, but control precisely what you want to allow callers to do.

Jean
If you don't intend subclasses of `ConcreteClass` to override `DataType`, you might be better putting both the `type` and `val` aliases in the companion object (instead of having one in the class). This is how aliases in the `scala` package object work.
Ben Lings
You are very right indeed. I'll do this from now on. Thanks.
Jean