Enforce the name of a case object - scala

Given this code:
sealed trait Parent
case object GetOne extends Parent
case object GetTwo extends Parent
Is it possible in Scala to enforce those constraints:
Parent can only be extended by case object
The child case object of Parent must have their names start by Get.
Is it possible?

Parent can only be extended by case object
You may get close using Singleton.
(as mentioned by #MateuszKubuszok)
Here is an example:
sealed trait Foo extends Product with Serializable { self: Singleton => }
Then this works:
final case object A extends Foo
final case object B extends Foo
And this doesn't:
final case object A extends Foo
final case class B(blah: String) extends Foo
The child case object of Parent must have their names start by Get.
Not using standard Scala.
Maybe with macros or something like that, but really feels like a strange requisite; do you plan to get those instances through reflection? or what is the reason to wanting that?
(in any case, seems like something that may be better handled by code reviews and maybe a scalafix rule)

Try macros (with Shapeless)
import shapeless.ops.{coproduct, hlist}
import shapeless.{Coproduct, HList, LabelledGeneric}
import shapeless.ops.union.{Keys, Values}
def check[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[C <: Coproduct, K <: HList, V <: Coproduct]()(implicit
labelledGeneric: LabelledGeneric.Aux[A, C],
keys: Keys.Aux[C, K],
values: Values.Aux[C, V],
allKeysStartWithGet: hlist.LiftAll[StartsWithGet, K],
allValuesAreObjects: coproduct.LiftAll[IsObject, V]
) = null
}
import shapeless.Witness
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
trait StartsWithGet[S]
object StartsWithGet {
implicit def mkStartsWithGet[S <: Symbol]: StartsWithGet[S] = macro impl[S]
def impl[S <: Symbol : c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typ = weakTypeOf[S]
val witness = c.inferImplicitValue(
c.typecheck(tq"_root_.shapeless.Witness.Aux[$typ]", mode = c.TYPEmode).tpe,
silent = false
)
val str = c.eval(c.Expr[Witness.Lt[scala.Symbol]](
c.untypecheck(witness.duplicate)
)).value.name
if (str.startsWith("Get"))
q"new StartsWithGet[$typ] {}"
else c.abort(c.enclosingPosition, s"$str doesn't start with Get")
}
}
trait IsObject[A]
object IsObject {
implicit def mkIsObject[A]: IsObject[A] = macro impl[A]
def impl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typ = weakTypeOf[A]
if (typ.typeSymbol.isModuleClass)
q"new IsObject[$typ] {}"
else c.abort(c.enclosingPosition, s"$typ is not object")
}
}
sealed trait Parent
case object GetOne extends Parent
case object GetTwo extends Parent
check[Parent]() // compiles
sealed trait Parent
case object GetOne extends Parent
case object Two extends Parent
check[Parent]() // doesn't compile
sealed trait Parent
case object GetOne extends Parent
case class GetTwo() extends Parent
check[Parent]() // doesn't compile
Alternatively StartsWithGet can be defined via https://github.com/fthomas/singleton-ops
import shapeless.tag.##
import singleton.ops.{Require, StartsWith}
trait StartsWithGet[S]
object StartsWithGet {
implicit def mkStartsWithGet[S <: String](implicit
startsWith: Require[S StartsWith "Get"]
): StartsWithGet[Symbol ## S] = null
}

Parent can only be extended by case object
In Scala 3 you could define an enumeration
enum Parent {
case GetOne, GetTwo
}
which forces the members to be effectively case objects.

Related

Can Scala Companion Object Traits call a constructor of the class?

I'm trying to solve a problem that may not be possible in Scala.
I want to have a Trait to solve default constructors
trait Builder[T <: Buildable] {
def build(code: String): T = new T(code)
def build: T = new T("bar")
}
So extending the Trait on the companion object automatically has access to functions that creates the class with specific constructors and parameters
class A(code: String) extends Buildable
object A extends Builder[A]
Extending the Trait, the companion object has the constructors
A.build("foo")
A.build
Is this possible in Scala?
Also tried abstract classes, but hadn't had any success
trait Builder[T <: BuildableClass] {
def build(code: String): T = new T(code)
def build: T = new T("bar")
}
abstract class BuildableClass(code: String)
class A(code: String) extends BuildableClass(code)
object A extends Builder[A]
Thanks in advance
Edit: currently locked on Scala 2.12
Because of the type erasure, in ordinary code new T is allowed only for class type T, not an abstract type/type parameter.
In Scala, is it possible to instantiate an object of generic type T?
How to create an instance of type T at runtime with TypeTags
Class type required but T found
An alternative to runtime reflection (see #StanislavKovalenko's answer) is macros. new T is possible there because during macro expansion T is not erased yet.
import scala.language.experimental.macros
import scala.reflect.macros.blackbox // libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value
abstract class BuildableClass(code: String)
trait Builder[T <: BuildableClass] {
def build(code: String): T = macro BuilderMacros.buildImpl[T]
def build: T = macro BuilderMacros.buildDefaultImpl[T]
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
def buildImpl[T: WeakTypeTag](code: Tree): Tree = q"new ${weakTypeOf[T]}($code)"
def buildDefaultImpl[T: WeakTypeTag]: Tree = q"""new ${weakTypeOf[T]}("bar")"""
}
// in a different subproject
class A(code:String) extends BuildableClass(code)
object A extends Builder[A]
A.build("foo") // scalac: new A("foo")
A.build // scalac: new A("bar")
Alternative implementations:
trait Builder[T <: BuildableClass] {
def build(code: String): T = macro BuilderMacros.buildImpl
def build: T = macro BuilderMacros.buildDefaultImpl
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val tpe = c.prefix.tree.tpe.baseType(symbolOf[Builder[_]]).typeArgs.head
def buildImpl(code: Tree): Tree = q"new $tpe($code)"
def buildDefaultImpl: Tree = q"""new $tpe("bar")"""
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val symb = c.prefix.tree.symbol.companion
def buildImpl(code: Tree): Tree = q"new $symb($code)"
def buildDefaultImpl: Tree = q"""new $symb("bar")"""
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val tpe = c.prefix.tree.tpe.companion
def buildImpl(code: Tree): Tree = q"new $tpe($code)"
def buildDefaultImpl: Tree = q"""new $tpe("bar")"""
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val tpe = symbolOf[Builder[_]].typeParams.head.asType.toType
.asSeenFrom(c.prefix.tree.tpe, symbolOf[Builder[_]])
def buildImpl(code: Tree): Tree = q"new $tpe($code)"
def buildDefaultImpl: Tree = q"""new $tpe("bar")"""
}
One of the potential solution that uses a reflection looks a bit ugly, but it works.
import scala.reflect._
trait Builder[T <: Buildable] {
def build(code: String)(implicit ct: ClassTag[T]): T =
ct.runtimeClass.getConstructors()(0).newInstance(code).asInstanceOf[T]
def build(implicit ct: ClassTag[T]): T =
ct.runtimeClass.getConstructors()(0).newInstance("bar").asInstanceOf[T]
}
trait Buildable
class A(code: String) extends Buildable {
def getCode = code
}
object A extends Builder[A]
val a: A = A.build
println(a.getCode)
The problem is that your Builder trait doesn't know anything about how to construct your instances. You can get this info from runtime with reflection or from compile time with macros.
Found a much cleaner solution to this problem without using macros / reflection / implicits
trait Buildable
trait Builder[T <: Buildable] {
self =>
def apply(code: String): T
def build: T = self.apply("foo")
def build(code: String): T = self.apply(code)
}
case class A(code: String) extends Buildable {
def getCode: String = code
}
object A extends Builder[A]
A.build("bar").getCode
A.build.getCode

Scala generic method - No ClassTag available for T - when using Collection

I want to leverage Scala reflection to implicitly pass a ClassTag.
There are plenty solutions on StackOverflow on how to accomplish this.
import scala.reflect.ClassTag
// animal input
trait AnimalInput {}
case class DogInput() extends AnimalInput
case class CatInput() extends AnimalInput
// animals
trait Animal[T <: AnimalInput] {
def getInput(implicit ct: ClassTag[T]): Class[T] = {
ct.runtimeClass.asInstanceOf[Class[T]]
}
}
object Dog extends Animal[DogInput] {}
object Cat extends Animal[CatInput] {}
I can test that this is working well:
println(Dog.getInput) // Success: "DogInput"
println(Cat.getInput) // Success: "CatInput"
The problem is, the second I reference these objects in any collection, I run into trouble:
// Failure: "No ClassTag available for animal.T"
List(Dog, Cat).foreach(animal => println(animal.getInput))
I think I understand why this is happening but I'm not sure how to work around it.
Thank you in advance for your help!
Actually, I can't reproduce No ClassTag available for animal.T. Your code compiles and runs in Scala 2.13.9:
https://scastie.scala-lang.org/DmytroMitin/lonnNg0fR1qb4Lg7ChDBqg
Maybe by failure you meant that for collection you don't receive classes DogInput, CatInput.
Actually, I managed to reproduce No ClassTag available for animal.T for type member T <: AnimalInput rather than type parameter: https://scastie.scala-lang.org/v79Y37eDRXuoauWA9b8uhQ
This question is very close to recent question Trying to extract the TypeTag of a Sequence of classes that extend a trait with different generic type parameters
See the reasons there.
Either use a heterogeneous collection
object classPoly extends Poly1 {
implicit def cse[T <: AnimalInput : ClassTag, A](implicit
ev: A <:< Animal[T]
): Case.Aux[A, Class[T]] =
at(_ => classTag[T].runtimeClass.asInstanceOf[Class[T]])
}
(Dog :: Cat :: HNil).map(classPoly).toList.foreach(println)
// class DogInput
// class CatInput
or use runtime reflection
trait Animal[T <: AnimalInput] {
def getInput: Class[T] = {
val classSymbol = runtimeMirror.classSymbol(this.getClass)
val animalSymbol = typeOf[Animal[_]].typeSymbol
val extendeeType = classSymbol.typeSignature.baseType(animalSymbol)
val extenderSymbol = extendeeType.typeArgs.head.typeSymbol.asClass
runtimeMirror.runtimeClass(extenderSymbol).asInstanceOf[Class[T]]
}
}
List(Dog, Cat).foreach(animal => println(animal.getInput))
// class DogInput
// class CatInput
The easiest is
trait Animal[T <: AnimalInput] {
def getInput: Class[T]
}
object Dog extends Animal[DogInput] {
val getInput = classOf[DogInput]
}
object Cat extends Animal[CatInput] {
val getInput = classOf[CatInput]
}
One more option is magnet pattern (1 2 3 4 5 6)
trait AnimalMagnet[T <: AnimalInput] {
def getInput: Class[T]
}
import scala.language.implicitConversions
implicit def animalToMagnet[A, T <: AnimalInput : ClassTag](a: A)(implicit
ev: A <:< Animal[T]
): AnimalMagnet[T] = new AnimalMagnet[T] {
override def getInput: Class[T] = classTag[T].runtimeClass.asInstanceOf[Class[T]]
}
List[AnimalMagnet[_]](Dog, Cat).foreach(animal => println(animal.getInput))
//class DogInput
//class CatInput
Also you can move ClassTag implicit from the method to the trait (and make the trait an abstract class)
abstract class Animal[T <: AnimalInput](implicit ct: ClassTag[T]) {
def getInput: Class[T] = ct.runtimeClass.asInstanceOf[Class[T]]
}
List(Dog, Cat).foreach(animal => println(animal.getInput))
// class DogInput
// class CatInput

How to use circe with generic case class that extends a sealed trait

I have this minimal example, I want to create encoders/decoders with circe semi-automatic derivation for the generic case class A[T]
import io.circe.{Decoder, Encoder}
import io.circe.generic.semiauto._
import io.circe.syntax._
sealed trait MyTrait
object MyTrait {
implicit val encoder: Encoder[MyTrait] = deriveEncoder
implicit val decoder: Decoder[MyTrait] = deriveDecoder
}
case class A[T](value: T) extends MyTrait
object A {
implicit def encoder[T: Encoder]: Encoder[A[T]] = deriveEncoder
implicit def decoder[T: Decoder]: Decoder[A[T]] = deriveDecoder
}
This codes does not compile and instead outputs this error
could not find Lazy implicit value of type io.circe.generic.encoding.DerivedAsObjectEncoder[A]
And the same for the decoder
What Am I doing wrong here and how can I get it working?
There are few issues. One is that MyTrait Encoder/Decoder will try to dispatch encodeing/decoding into codecs for the subtypes - since e thtrait is sealed all possible traits are known, so such list can be obtained by compiler.
BUT
While MyTrait trait does not take type parameters, its only implementation A takes. Which basically turns it into an existential type.
val myTrait: MyTrait = A(10)
myTrait match {
case A(x) =>
// x is of unknown type, at best you could use runtime reflection
// but codecs are generated with compile time reflection
}
Even if you wanted to make these codecs manually, you have no way of doing it
object Scope {
def aEncoder[T: Encoder]: Encoder[A[T]] = ...
val myTraitEncoder: Encoder[MyTrait] = {
case A(value) =>
// value is of unknown type, how to decide what Encoder[T]
// pass into aEncoder?
}
}
For similar reasons you couldn't manually implement Decoder.
To be able to implement codec manually (which is kind of prerequisite to being able to generate it), you can only remove type parameters as you go into subclasses, never add them.
sealed trait MyTrait[T]
case class A[T](value: T) extends MyTrait[T]
This would make it possible to know what kind of T is inside A since it would be passed from MyTrait, so you could write your codec manually and they would work.
Another problem is that reliable generation of ADT's usually require some configuration, e.g. whether or not to use discimination field. And that is provided by circe-generic-extras. Once you use it, (semi)automatic derivation is possible:
import io.circe.{Decoder, Encoder}
import io.circe.generic.extras.Configuration
import io.circe.generic.extras.semiauto._
import io.circe.syntax._
// can be used to tweak e.g. discriminator field name
implicit val config: Configuration = Configuration.default
sealed trait MyTrait[T]
object MyTrait {
implicit def encoder[T: Encoder]: Encoder[MyTrait[A]] = deriveEncoder
implicit def decoder[T: Decoder]: Decoder[MyTrait[A]] = deriveDecoder
}
case class A[T](value: T) extends MyTrait[T]
object A {
implicit def encoder[T: Encoder]: Encoder[A[T]] = deriveEncoder
implicit def decoder[T: Decoder]: Decoder[A[T]] = deriveDecoder
}
Among other solutions to the problem, if you really didn't want to use type parameter in MyTrait but have polymorphism in A would be to replace umbound, generic A with another ADT (or sum type in Scala 3), so that list of all possible implementations would be known and enumerated.
// x is of unknown type, at best you could use runtime reflection
I'll just comment that in principle you can define Decoder with runtime reflection (runtime compilation) based on the class of value in case class A[T](value: T)
sealed trait MyTrait
case class A[T](value: T) extends MyTrait
object A {
// custom codecs
implicit val intEnc: Encoder[A[Int]] = new Encoder[A[Int]] {
override def apply(a: A[Int]): Json = Json.obj("A" -> Json.obj("value" -> Json.fromInt(a.value)))
}
implicit val strEnc: Encoder[A[String]] = new Encoder[A[String]] {
override def apply(a: A[String]): Json = Json.obj("value" -> Json.fromString(a.value))
}
implicit val boolEnc: Encoder[A[Boolean]] = new Encoder[A[Boolean]] {
override def apply(a: A[Boolean]): Json = Json.fromBoolean(a.value)
}
}
val Integer = classOf[Integer]
val Boolean = classOf[java.lang.Boolean]
def primitiveClass[T](runtimeClass: Class[_]): Class[_] = runtimeClass match {
case `Integer` => classOf[Int]
case `Boolean` => classOf[Boolean]
//...
case _ => runtimeClass
}
object MyTrait {
implicit val encoder: Encoder[MyTrait] = new Encoder[MyTrait] {
override def apply(a: MyTrait): Json = a match {
case a1#A(t) =>
tb.eval(q"implicitly[io.circe.Encoder[A[${rm.classSymbol(primitiveClass(t.getClass)).toType}]]]")
.asInstanceOf[Encoder[A[_]]]
.apply(a1)
}
}
}
(A(1): MyTrait).asJson.noSpaces // {"A":{"value":1}}
(A("a"): MyTrait).asJson.noSpaces //{"value":"a"}
(A(true): MyTrait).asJson.noSpaces //true
But for case class A[T](value: Int) such trick would be impossible.

Covariant return type implementation

I'm trying to implement a covariant return type for a method in Scala. Let's assume we have the following scenario:
class Animal
class Dog extends Animal
class Cat extends Animal
abstract class M[-T]{
def get[U <: T](): U
}
val container = new M[Animal] {
override def get[U <: Animal](): U = ???
}
How should I do that?
If you're just curious, for example you can use Shapeless
import shapeless.{Generic, HNil}
def get[U <: Animal]()(implicit generic: Generic.Aux[U, HNil]): U =
generic.from(HNil)
get[Dog] // Dog() for case class, Dog#34340fab otherwise
get[Cat] // Cat() for case class, Cat#2aafb23c otherwise
get[Nothing] // doesn't compile
get[Null] // doesn't compile
get[Cat with Dog] // doesn't compile
Or you can use a macro
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def get[U <: Animal](): U = macro getImpl[U]
def getImpl[U: c.WeakTypeTag](c: blackbox.Context)(): c.Tree = {
import c.universe._
q"new ${weakTypeOf[U]}"
}
Or you can use runtime reflection
import scala.reflect.runtime.universe._
import scala.reflect.runtime
def get[U <: Animal : TypeTag](): U = {
val typ = typeOf[U]
val constructorSymbol = typ.decl(termNames.CONSTRUCTOR).asMethod
val runtimeMirror = runtime.currentMirror
val classSymbol = typ.typeSymbol.asClass
val classMirror = runtimeMirror.reflectClass(classSymbol)
val constructorMirror = classMirror.reflectConstructor(constructorSymbol)
constructorMirror().asInstanceOf[U]
}
(see also example with Java reflection in #KrzysztofAtłasik's answer.)
Or you just can introduce a type class and define its instances manually
trait Get[U <: Animal] {
def get(): U
}
object Get {
implicit val dog: Get[Dog] = () => new Dog
implicit val cat: Get[Cat] = () => new Cat
}
def get[U <: Animal]()(implicit g: Get[U]): U = g.get()
Alternatively, you could use reflection to create new instances. You just need to get implicit classTag:
import scala.reflect.ClassTag
class Animal
class Dog extends Animal
class Cat extends Animal
abstract class M[-T] {
def get[U <: T](implicit ct: ClassTag[U]): U
}
val container = new M[Animal] {
override def get[U <: Animal](implicit ct: ClassTag[U]): U =
//it gets no argument constructor so obviosly it will only work if your classes has no params
ct.runtimeClass.getConstructor().newInstance().asInstanceOf[U]
}
container.get[Dog]

Implicit macro. Default implicit value. How?

I don't even know how to ask the question.
I have a macro that creates an instance of IsEnum[T] for a type T.
I'm doing testing for it, and want to make sure that the implicit is not found for types that are not sealed, or that, in general, don't meet the requirements of an enum.
So I created this method for testing
def enumOf[T](implicit isEnum:IsEnum[T] = null) = isEnum
And then I ensure that enumOf[NotAnEnum] == null
But instead, it fails at compile time.
One thing is the macro erroring. Another thing is the macro just not applying for a given case. How to make that distinction when creating macros?
Edit: I've used c.abort and c.error, both giving me the same results.
Sounds like you didn't make your macro materializing type class IsEnum whitebox. Normally implicit macros should be whitebox.
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
trait IsEnum[T]
object IsEnum {
implicit def mkIsEnum[T]: IsEnum[T] = macro mkIsEnumImpl[T]
def mkIsEnumImpl[T: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typ = weakTypeOf[T]
val classSymbol = typ.typeSymbol.asClass
if (!classSymbol.isTrait || !classSymbol.isSealed) c.abort(c.enclosingPosition, s"$typ must be sealed trait")
val symbols = classSymbol.knownDirectSubclasses
symbols.collectFirst {
case symbol if !symbol.isModuleClass || !symbol.asClass.isCaseClass =>
c.abort(c.enclosingPosition, s"${symbol.asClass.toType} must be case object")
}
q"new IsEnum[$typ] {}"
}
}
def enumOf[T](implicit isEnum: IsEnum[T] = null) = isEnum
Usage:
sealed trait A
object A {
case object B extends A
case object C extends A
case class D() extends A
}
enumOf[A] //null
sealed trait A
object A {
case object B extends A
case object C extends A
class D extends A
}
enumOf[A] //null
sealed trait A
object A {
case object B extends A
object C extends A
}
enumOf[A] //null
trait A
object A {
case object B extends A
case object C extends A
}
enumOf[A] //null
sealed trait A
object A {
case object B extends A
case object C extends A
}
enumOf[A] //App$$anon$1#47f37ef1
Runtime of macros is compile time of main code. If a blackbox macro (even implicit blackbox macro) throws an exception then it will be a compile error during compilation of main code. If a whitebox implicit macro throws an exception then during compilation of main code the implicit will be silently removed from candidates.
https://docs.scala-lang.org/overviews/macros/blackbox-whitebox.html