Scala generics - simplify number of generic arguments - scala

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

Related

Extract parameterised type from self in scala

I have class with parameterised type
abstract class Worker[T] {
def conf1: ...
def conf2: ...
def doWork ...
}
abstract class SpecializedWorker[T: TypeTag] extends Worker[T] {
//some behavior overriden (used fields from Trait that i want create)
}
I want to create trait that can be mixed to Worker.
trait Extension {
self: Worker[_] =>
def someParameter: ... // only several workers can have that. thats why i need trait
def produceSpecializedWorker = new SpecializedWorker[???]() {}
}
How to extract type information from self to replace ???
Here is a way to extract a type parameter:
trait Extension {
self: Worker[_] =>
def mkSpWorker[T](implicit ev: this.type <:< Worker[T]) = new SpecializedWorker[T]() {}
}
But I wouldn't recommend that :) You could define a type member in Worker that can be used in Extension.
abstract class Worker[T] {
type TT = T
}
trait Extension {
self: Worker[_] =>
def mkSpWorker = new SpecializedWorker[TT]() {}
}
Or you could just consider giving Extension a type parameter. It's not such a big deal, I think.

Scala trait method restricted to implementing type

So I'm having some trouble with what I think is a pretty simple situation in trait implementation, and I'm hoping there is some simple solution that I'm missing. I'd like to have a method on a trait that accepts as a parameter (and returns as a value only the type of the concrete implementation that it is being called on. Specifically:
trait Foo {
type ConcreteFoo // what to put here?
def combine(that:ConcreteFoo):ConcreteFoo
}
class FooImpl1 extends Foo {
def combine(that:FooImpl1):FooImpl1 = {
// implementation
}
}
class FooImpl2 extends Foo {
def combine(that:FooImpl2):FooImpl2 = {
// implementation
}
}
Right now I have a type Self = FooImpl on the implementing classes, but I'd rather have something on the trait that takes care of it if possible.
This is exactly F-Bounded Polymorphism:
trait Foo[T <: Foo[T]]
def combine(that: T): T
}
class FooImpl1 extends Foo[FooImpl1] {
def combine(that: FooImpl1): FooImpl1 = {
???
}
}
class FooImpl2 extends Foo[FooImpl2] {
def combine(that: FooImpl2): FooImpl2 = {
???
}
}
You can add a type parameter to your trait like this:
trait Foo[A] {
def combine(that: A): A
}
class FooImpl1 extends Foo[FooImpl1] {
override def combine(that: FooImpl1): FooImpl1 = ???
}
class FooImpl2 extends Foo[FooImpl2] {
override def combine(that: FooImpl2): FooImpl2 = ???
}

Reference to self type in parameterized trait

I have the following problem: I would like to have an 'instance' (parameterized trait) and 'configuration', and the latter is parameterized by the instance type:
trait Kind
trait Kind1 extends Kind
trait Kind2 extends Kind
trait Instance[T <: Kind] {
def configuration: InstanceConfiguration[Instance[_]]
}
trait InstanceConfiguration[+T <: Instance[_]] {
}
class AInstance extends Instance[Kind1] {
override def configuration: AConfiguration = ???
}
class AConfiguration extends InstanceConfiguration[AInstance] {
}
class BInstance extends Instance[Kind1] {
override def configuration: AConfiguration = ???
}
So, the issue is that InstanceConfiguration[Instance[Kind2]] cannot be used as a configuration for Instance[Kind1], but now it is too generic, and I'd like compiler to give out error on BInstance.configuration.
So how do I change definition of configuration in the Instance trait to reference the concrete InstanceConfiguration of the concrete type?
You need to use F-Bounded polymophism. I recommend reading the section in Twitter's Scala School, but in brief, Instance needs to take the concrete type as a type parameter:
trait Kind
trait Kind1 extends Kind
trait Kind2 extends Kind
trait Instance[A <: Instance[A, T], T <: Kind] {
self: A =>
def configuration: InstanceConfiguration[A]
}
trait InstanceConfiguration[+T <: Instance[_, _]] {
}
class AInstance extends Instance[AInstance, Kind1] {
override def configuration: AConfiguration = ???
}
class AConfiguration extends InstanceConfiguration[AInstance] {
}
class BInstance extends Instance[BInstance, Kind1] {
override def configuration: AConfiguration = ???
}

Scala trait runtime class from type parameter

I have a scala trait [this trait does not compile]
trait MyTrait[T <: Enum] {
def myMethod(name: String): T = {
MyJavaClass.staticMethod(name, classOf[T])
}
}
And a Java class
public class MyJavaClass {
public static <T extends Enum> T staticMethod(String name, Class<T> c) {
return (T) T.valueOf(c, name);
}
}
How can I make the trait valid scala? What I'm currently doing is adding a Class[T] field like this
trait MyTrait[T <: Enum] {
val t: Class[T]
def myMethod(name: String): T = {
MyJavaClass.staticMethod(name, t)
}
}
but I don't like having to add a t field to all classes that want to use this trait.
Nice and common way of working around type erasure in Scala is to use ClassTags.
They're usually passed as implicit parameters. Unfortunately, traits can't take constructor parameters, so the best that we can have is:
import scala.reflect.ClassTag
trait MyTrait[T <: Enum] {
val ttag: ClassTag[T]
def myMethod(name: String): T = {
MyJavaClass.staticMethod(name, ttag.runtimeClass.asInstanceOf[Class[T]])
}
}
Then, every class extending MyTrait must be defined like this:
class MyClass[T <: Enum](/*your params, if any*/)(implicit val ttag: ClassTag[T]) extends MyTrait[T] {
/*your class body*/
}
Then, if you have some concrete enum MyEnum, you can create instances of your class seamlessly:
new MyClass[MyEnum](/*your params, if any*/)

scala override trait with generic method

I have 3 classes:
class AClass
class Base { val a = "a" }
class BaseOne extends Base { val b = "b" }
class BaseTwo extends Base { val c = "c" }
I want to extend a trait which contains a generic method, I'm not allowed to change the trait
trait Converter {
def toAClass[T <: Base](e: T): AClass
def fromAClass[T <: Base](s: AClass): T
}
I want to extend it in several different objects
object ConverterBaseOne extends Converter {
// ERROR
override def toAClass(e: BaseOne) : AClass = { printf(e.b) } // b is known
override def fromAlcass(a: AClass) : BaseTwo = {....}
}
I know there is a way to do it with class parameter: trait Converter[T <: Base]
and also saw this post https://stackoverflow.com/a/4627144/980275
I'm asking if there is a solution without changing the trait ???
Thank you
You are changing the signature of the method, so it is not a legal override, it would break polymorphism. You must either parametrize the Converter trait or use another method name.
You can, however, receive a Base object and cast it, but it is not recommended practice since it may result in an exception at runtime:
object ConverterBaseOne extends Converter {
override def toAClass[T <: Base](e: T): AClass = {
printf(e.asInstanceOf[BaseOne].b)
// ...
}
}