Default type parameter in inheritence - scala

Say I have the following classes:
class A[T] { ... }
abstract class B[T1,T2](t: T1)(implicit ev: A[T2]) {
...
}
On some instances, when I inherit from B, the type for T2 is the same as that for T1. Is there I way I can define my class to avoid having to specify this explicitly?
So rather than having to do:
class C extends B[String, String]("Some string") {
...
}
Can I have the compiler some how infer this so I only need to write:
class C extends B("Some string") {
...
}

I think a type alias should work:
type B1[T] = B[T, T]
class C extends B1("Some string") {
...
}

Related

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

Scala: return a parametrized instance

I cannot make work the following code:
object Factory {
def apply[U <: Cda](type: MyType.Value): MyUtilTrait[U] = {
type match {
case MyType.Value.one => MyOneUtilCustom
case MyType.Value.two => MyTwoUtilCustom
}
}
}
=> Expression of type Factory.MyType doesn't conform to expected type MyUtilTrait[U]
trait MyUtilTrait[T <: Cda] {}
object MyOneUtilCustom extends MyUtilTrait[CdaOneCustom] { }
object MyTwoUtilCustom extends MyUtilTrait[CdaTwoCustom] { }
case class CdaOneCustom(...) extends Cda {}
case class CdaTwoCustom(...) extends Cda {}
abstract class Cda(...) {}
object MyType extends Enumeration {
val one, two = Value
}
With the apply, I am supposed to return a MyUtilTrait parametrized with a subtype of Cda, so what's wrong?
It's almost completely impossible to implement this apply method with such a signature [1], because someone could come along, define
class Unobtanium extends Cda {
// implement all `Cda` methods by `???`
}
and then invoke
Factory.apply[Unobtanium](MyType.one)
How is a factory supposed to create a MyUtilTrait[Unobtanium], if it knows nothing about Unobtanium, and it is the first time it sees this strange type?
Use existential type instead:
abstract class Cda {}
case class CdaOneCustom() extends Cda {}
case class CdaTwoCustom() extends Cda {}
trait MyUtilTrait[T <: Cda] {}
object MyOneUtilCustom extends MyUtilTrait[CdaOneCustom] { }
object MyTwoUtilCustom extends MyUtilTrait[CdaTwoCustom] { }
object MyType extends Enumeration {
val one, two = Value
}
object Factory {
def apply(typ: MyType.Value): MyUtilTrait[_] = {
import MyType._
typ match {
case `one` => MyOneUtilCustom
case `two` => MyTwoUtilCustom
}
}
}
[1] Unless your MyUtilTrait[X] is something trivial, like Nil (which is a List[X] for any X), or Consumer[Any] of some sort, which does not actually care about the type parameter.

Scala: Return type of abstract method

I cannot figure out how to specify the return type of a method an abstract class A, if the same method of the concrete classes have different return (sub)types:
abstract class A {
def method: List[Common (?)] // I want to force all subclasses to define this method
}
class B1 extends A {
def method(a,b,c): List[Sub1] = {...}
}
class B2 extends A {
def method(a,b,c): List[Sub2] = {...}
}
I tried to define a common trait of Sub1 and Sub2:
abstract class Common // or abstract class
case class Sub1 extends Common
case class Sub2 extends Common
but I keep getting this:
Compilation error[class B1 needs to be abstract,
since method "method" in class A of type => List[Common] is not defined]
If I don't define the return type in class A, I get the same error with ... type => Unit ... instead.
How can I solve that?
def method: List[Common]
Is not the same as
// returns `List[Common]` to simplify things, but it would be the same if we returned a sub-type
def method(a: ?, b: ?, c: ?): List[Common] = {...}
The first is a parameterless method that returns a List[Common], and the second is a method with three parameters that returns a List[Common]. The compiler sees these as two completely different methods. The fact that they have the same name means nothing.
The compiler is complaining because def method: List[Common] is not defined in the subclasses of A.
This compiles:
abstract class Common // or abstract class
case class Sub1() extends Common
case class Sub2() extends Common
abstract class A {
def method(): List[Common]
}
class B1 extends A {
def method(): List[Sub1] = ???
}
class B2 extends A {
def method(): List[Sub2] = ???
}
All I have done is:
add the () to Sub1() and Sub2()
return List[Common] from A
EDIT
As #m-z mentioned, it works because every def method() has the same signature now.

How can I implement concrete class which extends trait defining a method with type by the type parameter's type alias

I would like ask for some help for advanced scala developers. My problem is that I would like to access a type alias belonging to a type parameters of a class' parent.
case class MyModel(foo: String = "bar")
case class MyDispatcher()
trait Module[M, D] {
type Dispatcher = D
type Model = M
}
trait MySpecificModule[A <: Module[_, _]] {
def dispatcher(): A#Dispatcher
}
class ModuleClass extends Module[MyModel, MyDispatcher] {
//...
}
class MySpecificModuleClass extends MySpecificModule[ModuleClass] {
override def dispatcher(): MyDispatcher = MyDispatcher()
}
So basically MySpecificModule extends a generic trait, and should know the type of the dispatcher method. In this case of MySpecificModuleClass it should be MyDispatcher. But when I try to compile this code I am getting compilation error because the type of the method, is not the same as defined: A#Dispatcher, however in the reality it is.
Error:(21, 18) overriding method dispatcher in trait MySpecificModule of type ()_$2;
method dispatcher has incompatible type
override def dispatcher(): MyDispatcher = MyDispatcher()
^
I would appreciate any advice you suggest. Thanks in advance,
Gabor
Resolved
case class MyModel(foo: String = "bar")
case class MyDispatcher()
trait AbstractModule {
type Dispatcher
type Model
}
trait Module[M, D] extends AbstractModule {
type Dispatcher = D
type Model = M
}
trait MySpecificModule[A <: AbstractModule] {
def dispatcher(): A#Dispatcher
}
class ModuleClass extends Module[MyModel, MyDispatcher] {
//...
}
class MySpecificModuleClass extends MySpecificModule[ModuleClass] {
override def dispatcher(): MyDispatcher = MyDispatcher()
}
I don't fully understand Scala's reasoning here, but if you get rid of type parameters, things start to work:
case class MyModel(foo: String = "bar")
case class MyDispatcher()
trait Module {
type Dispatcher
type Model
}
trait MySpecificModule[A <: Module] {
def dispatcher(): A#Dispatcher
}
class ModuleClass extends Module {
type Model = MyModel
type Dispatcher = MyDispatcher
//...
}
class MySpecificModuleClass extends MySpecificModule[ModuleClass] {
override def dispatcher(): MyDispatcher = MyDispatcher()
}
And if you really want to have those type params, you can introduce a helper trait:
trait AbstractModule[M, D] extends Module {
type Model = M
type Dispatcher = D
}
class ModuleClass extends AbstractModule[MyModel,MyDispatcher]

F-Bound Polymorphism with Abstract Types instead of Parameter Types?

How do I convert the following F-Bound Polymorphism to code using Abstract Types?
trait Organism[Self <: Organism[Self]] { self: Self =>
def reproduceWith(org:Self):Boolean
}
class Amoeba extends Organism[Amoeba] {
def reproduceWith(org:Amoeba) = //..code
}
There are various ways to do this. Here is one way that I like, that is similar to "parameterized modules"
OCaml or Agda.
When you define your Organism type, you split it into an abstract type Organism and a trait OrganismOps. Then you wrap both of these in a trait:
trait OrganismSystem {
type Organism <: OrganismOps
trait OrganismOps {
def reproduceWith(org: Organism): Boolean
}
}
Because they are wrapped in the same trait, OrganismOps can see the Organism type.
Now if you want to create a concrete instance of these things, you would do this:
object MyOrganismSystem extends OrganismSystem {
case class Organism(species: String) extends OrganismOps {
def reproduceWith(org: Organism) = species == org.species
}
}
And if you want to define methods that operate generically on organism systems, you would have them take in an OrganismSystem as a parameter, or, equivalently, wrap them in a class that takes an OrganismSystem as a parameter:
class UsesGenericOrganismSystem(system: OrganismSystem) {
import system._
def allCompatible(organisms: Traversable[Organism]): Boolean =
organisms.toSeq.combinations(2) forall {
case Seq(o1, o2) => o1.reproduceWith(o2)
}
}