How to use Manifest with Enumeration in Scala? - scala

If I have the following Scala code:
trait BaseTrait[EnumType <: Enumeration] {
protected val enum: EnumType
protected val valueManifest: Manifest[EnumType#Value]
}
object MyEnum extends Enumeration {
val Tag1, Tag2 = Value
}
And I want to create a class which implements BaseTrait using MyEnum, I can do it like this:
class BaseClass[EnumType <: Enumeration]
(protected val enum: EnumType)
(implicit protected val valueManifest: Manifest[EnumType#Value])
extends BaseTrait[EnumType] {
}
class Test extends BaseClass(MyEnum)
But how can I do it without an intermediary base class? All other attempts always resulted in a compile error.

You did not write what you tried but my guess is that you had your class extend BaseTrait[MyEnum]. As MyEnum is an object the type MyEnum does not exist (unless you also define a class or trait with that name).
You have to explicitly supply the singleton type MyEnum.type as type parameter.
class Test extends BaseTrait[MyEnum.type] {
protected val enum = MyEnum
protected val valueManifest = manifest[MyEnum.type#Value]
}

Related

How do I limit the parameter types of a generic argument based on another parameter in Scala?

I'm trying to create a map of different configurations, where each configuration has a given key object and some options, e.g.
FirstConfig can be either:
FirstConfigOptionA
FirstConfigOptionB
SecondConfig can be either:
SecondConfigOptionA
SecondConfigOptionB
...
And I'm having trouble with general typing and signature of the setter function so it checks at compile time I'm supplying the correct objects, e.g.
// 1. this should compile normally
set(FirstConfig, FirstConfigOptionA)
// 2. should NOT compile due to `SecondConfigOptionA` parameter not being a valid option for `FirstConfig`
set(FirstConfig, SecondConfigOptionA)
So far, my attempts still allow the second case above to compile.
abstract sealed class Configuration
trait OptionKey[T <: Configuration] {}
trait OptionVariant[T <: Configuration] {}
// First Config
trait FirstConfig extends Configuration
object FirstConfigKey extends OptionKey[FirstConfig];
object FirstConfigOptionA extends OptionVariant[FirstConfig]
object FirstConfigOptionB extends OptionVariant[FirstConfig]
// Second Config
trait SecondConfig extends Configuration
object SecondConfigKey extends OptionKey[SecondConfig];
object SecondConfigOptionA extends OptionVariant[SecondConfig]
object SecondConfigOptionB extends OptionVariant[SecondConfig]
def set[T](k: OptionKey[T], v: OptionVariant[T]): Unit = {}
set(FirstConfigKey, FirstConfigOptionA)
set(FirstConfigKey, SecondConfigOptionA) // This still compiles
I've also tried using Enumerations with similar results:
object FirstConfig extends Enumeration {
type FirstConfig = Value
val FirstConfigOptionA, FirstConfigOptionB = Value
}
object SecondConfig extends Enumeration {
type SecondConfig = Value
val SecondConfigOptionA, SecondConfigOptionB = Value
}
def set(k: Enumeration, v: Enumeration#Value): Unit = {}
set(FirstConfig, FirstConfig.FirstConfigOptionA)
set(FirstConfig, SecondConfig.SecondConfigOptionA) // This still compiles
What is the correct way to express this relationship between a config and its available options or what should be set's signature to enforce it?
What about using path-dependant types like this:
trait Configuration {
sealed trait OptionKey
val key: OptionKey
sealed trait OptionVariant
}
object Configuration {
def set(config: Configuration)(variant: config.OptionVariant): Unit = {
println(s"${config} - ${config.key} - ${variant}")
}
}
case object FirstConfig extends Configuration {
private case object FirstConfigKey extends OptionKey
override final val key: OptionKey = FirstConfigKey
case object FirstConfigOptionA extends OptionVariant
case object FirstConfigOptionB extends OptionVariant
}
case object SecondConfig extends Configuration {
private case object SecondConfigKey extends OptionKey
override final val key: OptionKey = SecondConfigKey
case object SecondConfigOptionA extends OptionVariant
case object SecondConfigOptionB extends OptionVariant
}
You can see it working as expected here.
Why do you need to store them as key/value pairs? You can just represent it as an algebraic data type:
enum FirstConfig:
case OptionA
case OptionB
enum SecondConfig:
case OptionA
case OptionB
enum Config:
case First(value: FirstConfig)
case Second(value: SecondConfig)
def set(config: Config): Unit = …

Scala generics - simplify number of generic arguments

I have this class defined as follows:
abstract class MyHelper[T, E <: BaseHelper[T]](implicit clsTag: ClassTag[E]) {
val all: Array[E]
def parse(t: T): Try[E] = { ... }
}
and this is how I am using it:
trait IntHelper extends BaseHelper[Int] {}
object MyIntHelper extends MyHelper[Int, IntHelper] { }
How do I simplify MyHelper class definition to accept only the inner generic type T instead of passing two types, E and T?
There's no need for you to directly enforce T in MyHelper since you're only using E itself.
So something like this should be fine.
abstract class MyHelper[E <: BaseHelper[_]](implicit clsTag: ClassTag[E]) {
val all: Array[E]
}
A more fleshed out example looks like:
trait BaseHelper[T] {}
trait IntHelper extends BaseHelper[Int]
abstract class MyHelper[E <: BaseHelper[_]](implicit clsTag: ClassTag[E]) {
val all: Array[E]
}
object MyIntHelper extends MyHelper[IntHelper] {
override val all = Array(new IntHelper{}, new IntHelper{})
}
// just to ensure it works
MyIntHelper.all

Create a new object extending a trait and using early definition syntax

How to create an objectthat extends a trait and uses early definition syntax?
Let's say we have two traits:
trait Trait {
val value : String
}
trait Simple
Let's say we have also a simple class:
class Class
We can create a new object of type Class and make it extend a Simple trait:
new Class extends Simple
Is it possible to create a new object of type Class that extends the Trait and uses the early definition syntax to set value member? I tried something like:
new Class extends { override val value = "42" } with Trait
But this gives a syntax error:
Error:(12, 17) ';' expected but 'extends' found.
new Class extends { val value = "42" } with Trait
trait T { val value: String }
class C
new C with T { val value = "ok" }

Case object extending trait

We can supply parameter to a class extending trait with the same name as an abstract method like
trait Trr{
def m: String
}
case class Trrrr(m: String) extends Trr //fine
This example compiles fine. But I tried to do something like that with case objects and failed:
trait Command{
def name: String
}
case object Unload("unld") extends Command //compile error
Is there a way to write this concisely while leaving Command a trait, not an abstract class with parameter? I mean not like that:
case object Unload extends Command {
override def name: String = "unld"
}
or
abstract class Command(name: String)
case object Unload extends Command("unld")
case object Unload extends Command { val name = "unld" }
Object don't have arguments, things won't get any shorted than the above...
You can instantiate the trait directly like so:
val newTrr = new Trr { val m = "example" }
At this point you can use the newTrr value just like any class instance...
println(newTrr.m)
which will print out: "example".

Consider a trait as a subclass of another class

my question below is definately a nonsense but answering it will help me for another problem.
How force a trait to be mixed only by a specific class (or its subclass). I thought about use require() inside it :
abstract class Aclass(c_attribut1 : Int){
var attribut1 : Int = c_attribut1
def getAttribut1() : Int = this.attribut1
}
class Bclass extends Aclass(1) with Trait1{
}
class Cclass extends Aclass(2) with Trait1{
}
trait Trait1{
require(this.isInstanceOf[Aclass]);
def f() : Int = this.getAttribut1() * 2 // it obviously does not work
}
Then, I don't know how considere Trait1 as a Aclass (in order to avoid asInstanceOf every where). I know the function f should be in the Aclass but, as I said, I would like to know how properly force a trait to be mixed by a specific class and how to get messages of this class in the trait.
I wonder this because I need a trait is mixed by a specific class with template :
trait TraitBuiltHost extends Observable{
require(this.isInstanceOf[BuiltInfrastructure[_ <: TraitHostDefinition]]);
.
.
.
}
Thank you.
Self typing:
class MyClass1
class MyClass2
trait MyTrait {
self: MyClass1 =>
val i = 1
}
scala> new MyClass1 with MyTrait
res0: MyClass1 with MyTrait = $anon$1#3f0762f6
scala> new MyClass2 with MyTrait
<console>:1: error: illegal inheritance;
self-type MyClass2 with MyTrait does not conform to MyTrait's selftype MyTrait with MyClass1
new MyClass2 with MyTrait
^
See also Self references part of scala tag wiki.