Scala type alias including companion object [beginner]
Asked Answered
A

2

7

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 ?

Aquanaut answered 13/10, 2010 at 3:25 Comment(0)
A
7

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.

Aquanaut answered 13/10, 2010 at 4:47 Comment(3)
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.Kilocycle
Except d is type List[Nothing]Butter
I am trying to do this also, but I am looking for some way to write val d = DataType(arg1, arg2) and have d be known to the type system as DataType but the underlying type to be ListGodman
D
5

What about this?

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

Doorstop answered 13/10, 2010 at 4:26 Comment(1)
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 :)Aquanaut

© 2022 - 2024 — McMap. All rights reserved.