2

I want to get the instance of a singleton type in Scala, is this possible?

Example: (I know it can be done easier in this case)

sealed trait Animal
case object Dog extends Animal
case object Cat extends Animal

trait Person {
  def name: String
  // Is there a "FavoriteAnimal.instance" syntax?
  def mostImportantThings = (FavoriteAnimal.instance, name)
  protected type FavoriteAnimal <: Animal with scala.Singleton
}

case class DogPerson(override val name: String) extends Person {
  override type FavoriteAnimal = Dog.type
}

case class CatPerson(override val name: String) extends Person {
  override type FavoriteAnimal = Cat.type
}
7
  • 2
    What is scala.Singleton? Commented Feb 20, 2019 at 13:06
  • @Thilo It's not in Scaladoc (still) but it is the type extended by singleton types of objects and literals (see docs.scala-lang.org/sips/42.type.html). Commented Feb 20, 2019 at 17:13
  • @AlexeyRomanov That's not just not in Scaladoc, it is not implemented in mainline Scala 2.12, either, is it? Commented Feb 20, 2019 at 23:30
  • 2
    @Thilo it is implemented, try def onlySingleton(arg: Singleton): String = arg.toString: scastie.scala-lang.org/kU481gG3Rtih0rt6dEF2ag Commented Feb 21, 2019 at 7:32
  • 1
    There are certainly other types which don't have a .class file. Don't remember which at the moment. But I don't know any which are as undocumented. Commented Feb 21, 2019 at 20:31

2 Answers 2

3

Using shapeless.Witness correct syntax is

sealed trait Animal
case object Dog extends Animal
case object Cat extends Animal

trait Person {
  def name: String
  def mostImportantThings(implicit 
    witness: Witness.Aux[FavoriteAnimal]
  ): (FavoriteAnimal, String) = (witness.value, name)
  protected type FavoriteAnimal <: Animal with scala.Singleton
}

case class DogPerson(override val name: String) extends Person {
  override type FavoriteAnimal = Dog.type
}

case class CatPerson(override val name: String) extends Person {
  override type FavoriteAnimal = Cat.type
}

DogPerson("A Dog Person").mostImportantThings // (Dog, A Dog Person)

Unfortunately in the current version of Shapeless (2.3.3) there is a bug and this code doesn't compile. But after fix it does.

Sign up to request clarification or add additional context in comments.

Comments

2

Maybe you want something like

sealed trait Animal
case object Dog extends Animal
case object Cat extends Animal

trait Person[A <: Animal] {
  def name: String
  def animal: A
  def mostImportantThings = (animal, name)
}

case class DogPerson(override val name: String) extends Person[Dog.type] {
  override val animal = Dog
}

case class CatPerson(override val name: String) extends Person[Cat.type] {
  override val animal = Cat
}

3 Comments

I know this is possible, I was more curious whether my exact use-case is possible. Your approach is not ideal in the real situation I'm trying solve
Can you describe that use-case in more detail? It seems that if you at compile time already know the type of the singleton object, then you might just as well write your code to specify the singleton instead of the type (because it is easier to go from singleton to type than the other way around). Without more knowledge of your use case, the end result appears equivalent.
it's partly interest, party that this would allow me to prevent changing a decent amount of code since the type is already available, but the instance is not.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.