Scala related trait, abstract types - scala

I have 2 related traits. Dao will be used be a class and DaoHelper will be used by Dao's companion object. I would like trait Dao to be able use functions defined in DaoHelper, the only way I could figure out how to do this is to define the companion trait as a val. However somehow companion expects its type to be D.this.T which I thought I has defined as a subtype of Doa. I am confused here. My apologies for the newb question, I come from a dynamic language background.
/test2.scala:14: overriding value companion in trait Dao of type Test.DaoHelper[D.this.T];
[error] value companion has incompatible type
[error] val companion = D
object Test extends App {
trait Dao {
type T <: Dao
val companion: DaoHelper[T]
def getHelpfulData = companion.help
}
trait DaoHelper[Dao] {
val help = "Some helpful data"
}
class D extends Dao {
val companion = D
}
object D extends DaoHelper[D]
}

companion has type DaoHelper[T], but T isn't specified anywhere in D, so how would the compiler know it is supposed to be D in class D? You can fix it by overriding it in D.
class D extends Dao {
type T = D
val companion = D
}

I don't quite understand what you are trying to do with class D, but you are getting this error because you are assigning D to companion in class D, but companion has type DaoHelper[T] as defined in Dao. Since D has type Dao and Dao is not a subtype of DaoHelper[T], this will not work.

Related

Witness that an abstract type implements a typeclass

I believe my understanding on this is correct but I'd like to check. When creating typeclasses, it feels neater to have them take a single type parameter, like TypeClass[A]. If the typeclass needs to be parameterized in other ways, abstract types can be used, and there is a comparison of the two approaches here:
Abstract types versus type parameters
So far as I have been able to figure out, one thing which is not mentioned in the link is that if using a type parameter, you can witness that the parameter implements a (different) typeclass, likeso:
trait IsValidForTC[A]
abstract class TCWithTypeParam[A, B] (implicit ev: IsValidForTC[B]) {}
If I use an abstract type, I cannot be sure that it implements IsValidForTC:
abstract class TCWithAbstractType[A] (implicit ev: IsValidForTC[B]) {
type B
} //not found: Type B
If so then this makes sense, but this difference isn't mentioned in the link above so I'd like to check.
Thanks!
It's your choice whether to put implicit constraints on class level or method level. This makes impact on when the implicits are resolved.
In a type-parameter type class with implicit parameter you don't constrain the type of type class (applied to type parameters), i.e. type TCWithTypeParam[A, B] can be used even if there is no implicit IsValidForTC[B] in a scope. What you do constrain is the constructor of type class. You can emulate this behavior for type-member type class in the following way. Make the constructor private and define apply method (or instance as it's called sometimes) in companion object with desired implicit constraint
abstract class TCWithAbstractType[A] private {
type B
}
object TCWithAbstractType {
def apply[A, _B: IsValidForTC]: TCWithAbstractType[A] { type B = _B } =
new TCWithAbstractType[A] { type B = _B }
}
You can add the witness, but it needs to be inside the class scope so it has access to B:
abstract class TCWithAbstractType[A] {
type B
implicit val ev: IsValidForTC[B]
}
But in practice this is often less convenient than the type parameter, because it has to be implemented explicitly, something like
new TCWithAbstractType[A] {
type B = ...
implicit val ev: IsValidForTC[B] = ...
}
while a constructor parameter just gets the implicit value from outer scope.
Note: this is a partial duplicate of my answer to your follow-up question, but left here in case someone stumbles on this question first.

Inherit from a class parametrized by an inner type

I would like to have a class B that inherits from a generic class A that is parametrized by an inner type of B. Specifically, I would like this (minimized example):
class A[T]
class B extends A[T] {
class T
}
Written like this, the compiler does not accept it. Is there any way to specify this inheritance relationship? (Using some different syntax, or some tricks.)
If not, what would be an official reference documenting that this is not possible?
Notes:
Yes, I want T to be an inner class. I do want separate instances of B to have incompatible types T.
This question considers the same situation but does not ask whether/how it is possible, but instead asks for other ways to write the same thing. (At least that's how the answers seem to interpret it.) In any case, that question is ten years old, and Scala may have evolved since.
Clarification: I want B to inherit from A, not from an inner class of A, or have an inner class of B inherit from A. The reason is that I want to use it in the following situation: A is a type class. B is supposed to provide a quick way to easily generate new classes of that type class (with minimal boilerplate). I want to the user of the class to do something like: implicit val X = createBInstance(), and then they will be able to use the type X.T and it will have type class A. The best I managed so far is to support the pattern val X = createBInstance(); implicit val xTypeclass = X.typeclass and use X.T. This means more boilerplate, the possibility to forget something, and it pollutes the namespace more (additional name xTypeclass). (For the very curious: A is MLValue.Converter, B is QuickConverter, and X is Header/RuntimeError/... in my code.)
You can try
class A {
type T
}
class B extends A {
class T
}
val b: B = new B
val t: b.T = new b.T
I made T a type member rather than type parameter.
Here a class overrides a type.
If you want to use T also as a type parameter you can introduce Aux-type
object A {
type Aux[_T] = A { type T = _T }
}
and use type A.Aux[T] as a replacement to your original A[T].
Now you're doing
trait A[X]
class B {
class T
/*implicit*/ object typeclass extends A[T]
}
val b = new B
implicit val b_typeclass: b.typeclass.type = b.typeclass
val b1 = new B
implicit val b1_typeclass: b1.typeclass.type = b1.typeclass
implicitly[A[b.T]]
implicitly[A[b1.T]]
Please notice that making object typeclass implicit is now useless.
Making object typeclass implicit would be useful if you made b, b1 objects rather than values
trait A[X]
class B {
class T
implicit object typeclass extends A[T]
}
object b extends B
object b1 extends B
implicitly[A[b.T]]
implicitly[A[b1.T]]
If you want to make B extend A then as earlier I propose to replace type parameter of A with a type member. A will still be a type class, just type-member type class rather than type-parameter type class
trait A {
type X
}
object A {
type Aux[_X] = A {type X = _X}
}
class B extends A {
type X = T
class T
}
implicit object b extends B
implicit object b1 extends B
implicitly[A.Aux[b.T]]
implicitly[A.Aux[b1.T]]

Automatic higher kinded type inference within generic methods

I'm struggeling a bit with higher kinded types and complilers type inference...
I do have the following classes:
sealed trait Foo[A] {
#JsonProperty val payload : List[A] = Nil
}
class Baa extends Foo[MyCoolClassOne]
class FooBaa extends Foo[MyCoolClassTwo]
Now i have a function, that calls a REST-API to get either a JSON-response representing Baa or FooBaa (or other subclasses of Foo, just mention 2 of them for this example).
def getContent[A, F <: Foo[A]](url: String) : List[A] = {
// call API
// use com.fasterxml.jackson.databind.ObjectMapper to deserialize
// psuedo code...
val response = mapper.readValue(responseFromAPI, classTag.runtimeClass.asInstanceOf[Class[F]])
return response.payload
}
I could then call the API to get my content:
def getBaa(urlToBaa:String) = getContent[MyCoolClassOne, Baa](urlToBaa)
or
def getFooBaa(urlToFooBaa:String) = getContent[MyCoolClassTwo, FooBaa](urlToFooBaa)
The question
Why do i need to pass both classTags to funtion getContent?
How can i avoid this?
My thoughts
Foo is a sealed trait. There are (in this example) only 2 classes extending it. Both classes are extending Foo with a specific type. Why is the compiler unable to infer the type correct, if i would define the function somethign like this:
def getContent[F <: Foo[A]](url: String) : List[A] = { ... }
i know, that the compiler will look for a class 'A' in this case. But how could i tell him, that it is the typeinformation of the subclass of Foo.
Or to be more precise, i don't care about the method declaration, but to pass an 'obvious' typeinformation to the function, each time i call it, is very annoing.

scala abstract type parameterized by `this.type`

Im trying to create Script and ScriptType classes. ScriptTypes would produce Scripts of a particular abstract type. Scripts would be parameterized by the ScritpType that created them.
My first attempt looked like this:
trait Script[Type <: ScriptType]
sealed trait ScriptType {
type S <: Script[this.type]
}
object ScriptType {
class Scala extends ScriptType {
type S = ScalaScript
}
}
import ScriptType._
case class ScalaScript(source: String) extends Script[Scala]
but im getting a error in compilation regarding the assigning of type S in ScriptType.Scala
Error:(10, 10) overriding type S in trait ScriptType with bounds <: Script[Scala.this.type];
type S has incompatible type
type S = ScalaScript
in this example is ScalaScript not a Script[Scala.this.type]?
ScalaScript is not a Script[Scala.this.type], since this.type means a singleton type that's unique for each Scala instance.
You can solve this by making Script contravariant:
trait Script[-Type <: ScriptType]
so that ScalaScript can be accepted as a subtype of Script[Scala.this.type], since Scala is a supertype of Scala.this.type (the singleton type of any instance of Scala).

how to force method to be implemented in concrete subclass from trait

I have a method in my trait
def controller: AnyRef
but my concrete class was not implementing that method and it was still compiling. The compiler doesn't let me add abstract to that method either. How can I create a method in a trait that forces it's implementer to implement it?
thanks,
Dean
The compiler enforces that concrete classes implement all the abstracts methods they inherit from superclasses and traits.
If your class was compiling it meant it wasn't concrete, i.e. it was a trait or an abstract class, and you can't force neither to implement the abstract method.
Of course, as soon as you try to obtain a concrete instance the compiler will raise an error as the method is not implemented.
Practical example in the REPL
scala> trait A { def controller: AnyRef }
defined trait A
scala> trait B extends A
defined trait B
scala> abstract class C extends A
defined class C
scala> class D extends A
<console>:8: error: class D needs to be abstract, since method controller in trait A of type => AnyRef is not defined
class D extends A
scala> new B { }
<console>:10: error: object creation impossible, since method controller in trait A of type => AnyRef is not defined
new B { }
^
scala> new C
<console>:10: error: class C is abstract; cannot be instantiated
new C
If you are not getting any compilation error for such case, I think your IDE has some problem, try refresh/clean your project.
If your trait has implementation of "controller" function, then the concrete class(non abstract class) extending trait need not have any implementation for "controller" function. That's the beauty of trait in Scala, not forcing all the concrete class to implement some common methods with same implementation.
well, there seems to be some weird scala issue occuring.
When you have a concrete subclass that has a
val controller = new Controller
it seems to affect the traits controller and having your trait call controller results in null being returned. Everything compiles just fine (though I think that might be a scala bug as I don't 'think' that should actually compile).
If it should compile, then can someone please explain why it compiles.