The access on Manifest seems to be tricky from a trait in scala.
How could this code compile in scala ?
trait SomeTraitOf[+A] {
def newInstanceOfA : A = /* necessary code to make it work */
}
(Related, it works fine as a parametized class :
class SomeTraitOf[A : Manifest] {
def newInstanceOfA(implicit m : Manifest[A]) : A =
m.erasure.newInstance.asInstanceOf[A]
}
but not with a covariant type parameter (+A))
Edit : The real stuff
sealed trait RootPeerProxy[+A] extends Proxy {
def peer: A
def self = peer
def peerManifest[B >: A](): Option[Manifest[B]]
private[scalavaadin] def newInstance() : Option[A]
}
trait PeerProxy[+A] extends RootPeerProxy[A] {
override def peerManifest[B >: A](): Option[Manifest[B]]
override def peer(): A = this.newInstance match {
case None => {throw new IllegalStateException("oups")}
case Some(a) => a
}
private[scalavaadin] override def newInstance() : Option[A] = peerManifest map { m => m.erasure.newInstance.asInstanceOf[A] }
}
Since traits cannot provide manifest for the parametized trait, the class implementing the trait should, but I am not getting it.
About covariance:
Since Manifest[A] is invariant in the parameter A, you can't do what you want directly. The usual strategy is to weaken the return type,
trait SomeTraitOf[+A] {
def newInstance[B >: A](implicit m: Manifest[B]): B = {
m.erasure.newInstance.asInstanceOf[B]
}
}
You can use the trait as follows,
class Parent
class Child extends Parent
val childBuilder = new SomeTraitOf[Child] {}
val parentBuilder: SomeTraitOf[Parent] = childBuilder
parentBuilder.newInstance // returns a Parent!
About View Bounds:
From your comment below, I guess you're also asking about "view bounds", which are just a concise way of declaring an implicit parameter. Your declaration
class SomeTraitOf[A : Manifest] { ...
basically translates to
class SomeTraitOf[A]()(implicit m0: Manifest[A]) { ....
Traits can't have view bounds because they can't take any (value) parameters. But that's not really a problem here, because in your example
class SomeTraitOf[A : Manifest] {
def newInstanceOfA(implicit m : Manifest[A]) : A =
m.erasure.newInstance.asInstanceOf[A]
}
you're not using the view bound! (You're using the parameter m instead.) If you wanted to use the view bound, you could do it this way:
class SomeTraitOf[A : Manifest] {
def newInstanceOfA : A =
implicitly[Manifest[A]].erasure.newInstance.asInstanceOf[A]
}
Related
I'm unable to define a Functor for my abstract class Foo[V : Monoid] that have a type constraint. this is because of the map method of Functor which takes a B parameters which is not a Monoid.
My question is how and where can I add such constraint ?
Here's a sample from what I'm trying to do :
import cats.Functor
import cats.kernel.Monoid
abstract class Foo[A : Monoid] {
val a: A
}
object Foo {
implicit def FooFunctor = new Functor[Foo] {
override def map[A, B](fa: Foo[A])(f: (A) => B) = new Foo[B] {
override val a: B = f(fa.a)
}
}
}
this raise the following exception :
Error:(12, 59) could not find implicit value for evidence parameter of type cats.kernel.Monoid[B]
override def map[A, B](fa: Foo[A])(f: (A) => B) = new Foo[B] {
My first solution was adding the constraint in the map definition (override def map[A, B : Monoid]) but this is not legal because this will change the definition of the function in Functor and will raise the Exception :
Error:(12, 18) method map overrides nothing.
Can anyone please help me get out of this ? any suggestion would be appreciated.
I think the main problems is that You're trying to mix sub-typing with type-classes. Should be:
trait Foo[A] extends Monoid[A] with Functor[A] {
val a: A
}
trait SomeADT
case class SomeValue(a: String) extends SomeADT
object SomeADT {
//evidence
}
I discovered that using abstract types affects the scala compiler ability to detect overrides and it interprets seemingly correct code as erroneous.
trait I {
type T
def doThings(t : T) : Unit
}
type IT[X] = I { type T = X}
trait A extends I {
override type T = AnyRef
def doThings(t : T) : Unit = println("A")
}
trait Z[X] extends I { this : IT[X] =>
abstract override def doThings(t : T) : Unit = {
println("Z")
super.doThings(t)
}
}
object Use {
val az = new A with Z[AnyRef] {}
}
The scala compiler fires such error:
OverloadAbstract.scala:44: error: object creation impossible, since method doThings in trait Z of type (t: this.T)Unit is marked `abstract' and `override', but no concrete implementation could be found in a base class
val az = new A with Z[AnyRef] {}
What is the proper way to express such relations between trait mixing and implementation?
For the comparison that code works fine:
trait I {
def doThings() : Unit
}
class A extends I {
def doThings() : Unit = println("A")
}
trait Z extends I {
abstract override def doThings() : Unit = {
println("Z")
super.doThings()
}
}
object Use {
val az = new A with Z {}
}
The real use case is to implement a forwarder for the akka.event.EventBus:
object PartialEventBus {
type ApplyEvent[E] = EventBus { type Event = E }
}
trait ForwardEventBus[E] extends EventBus { this : PartialEventBus.ApplyEvent[E] =>
def relay : PartialEventBus.ApplyEvent[E]
abstract override def publish(event : Event) : Unit = {
relay.publish(event)
super.publish(event)
}
}
Type parametrization for the ForwardEventBus is needed for compiler to match object-wide this.Event type with external relay.Event type. Compiler would fail without such hint because of scala's path-dependent types restrictions.
Perhaps I'm confused, shouldn't the question be "Why does abstract override succeed?" Section 5.2.4 of the spec covers abstract override, and it says, "The override modifier has an additional significance when combined with the abstract modifier. That modifier combination is only allowed for value members of traits."
I hope a language lawyer can weigh in, but it looks like this should not be legal.
I would like to define different implementations of immutable covariant priority queues. First of all, I would like that all of the implementations provide the following interface:
trait PQLike[T, This[_]] {
def isEmpty : Boolean
def enqueue[E >: T](x : E)(implicit ord : Ordering[E]) : This[E]
def dequeue[T] : This[T]
def first : T
}
so that This stands for the implementation's type constructor and T is the type of elements stored in the queue. For instance, if LinearPriorityQueue[T] is an implementation of a priority queue, then I want method enqueue for a LinearPriorityQueue to return a LinearPriorityQueue.
I also would like to define a PriorityQueue[T] trait (or abstract class) so that all implementations of priority queues can also be typed (in addition as to their specific type) as PriorityQueues.
I tried something like this:
trait PriorityQueue[+T] extends PQLike[T, _ <: PQLike[_,_]]
trait LinearPriorityQueue[+T] extends PriorityQueue[T] with PQLike[T,LinearPriorityQueue]
object EPQ extends LinearPriorityQueue[Nothing] {
def isEmpty = true
def first = throw new PriorityQueueException("first on empty queue")
def dequeue = throw new PriorityQueueException("dequeue on empty queue")
def enqueue[T](x : T) = NPQ(x,this)
}
case class NPQ[+T](x : T, q : LinearPriorityQueue[T]) extends LinearPriorityQueue[T] {
def isEmpty = false
def first = x
def dequeue = q
def enqueue[E >: T](y : E) = NPQ(y,this) // not real implementation
}
but I'm getting type errors related to kinds that I cannot fix.
Thanks
EDIT: OK, I have made some progress. This is currently compiling and working as expected, although I don't know if my solution could be simplified further (note that I have done some renamings):
trait IsPriorityQueue[+T, +Repr[+X] <: IsPriorityQueue[X,Repr]] {
def isEmpty : Boolean
def first : T
def enqueue[E >: T](x : E)(implicit ord : Ordering[E]) : Repr[E]
def dequeue : Repr[T]
}
trait PriorityQueue[+T] extends IsPriorityQueue[T, PriorityQueue]
trait LinearPriorityQueue[+T] extends PriorityQueue[T] with IsPriorityQueue[T,LinearPriorityQueue]
object EmptyLPQ extends LinearPriorityQueue[Nothing] {
def isEmpty = true
def first = throw new PriorityQueueException("first on empty queue")
def dequeue = throw new PriorityQueueException("dequeue on empty queue")
def enqueue[E](x : E)(implicit ord : Ordering[E]) = NodeLPQ(x,this)
}
case class NodeLPQ[+T](hd : T, tl : LinearPriorityQueue[T]) extends LinearPriorityQueue[T] {
def isEmpty = false
def first = hd
def dequeue = tl
def enqueue[E >: T](x : E)(implicit ord : Ordering[E]) =
if(ord.compare(x,hd)<0)
NodeLPQ(x,this)
else
NodeLPQ(hd,tl.enqueue(x))
}
I would like to get comments on my code and possible simplifications. I was also thinking that maybe trait PriorityQueue could be defined using an existential type (a PriorityQueue extends something that IsPriorityQueue for some representation) but haven't been able to express that.
EDIT: Does any one have some comments on my solution?
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)
// ...
}
}
The following code shows a shallow hierarchy where a type representing a generic binary operation is used to substantiate a parameterized abstract type in another shallow container hierarchy:
trait BinaryOp[A] extends ((A,A) => A)
trait Plus[A] extends BinaryOp[A]
trait Minus[A] extends BinaryOp[A]
trait BaseOps {
type T[A] <: BinaryOp[A]
def apply[B](one: B, two: B)(op: T[B]) = op(one, two)
}
case object PlusOp extends BaseOps {
override type T[A] = Plus[A]
}
case object MinusOp extends BaseOps {
override type T[A] = Minus[A]
}
object App {
val plus = new Plus[Int] {
def apply(i: Int, i2: Int) = i + i2
}
def main(a: Array[String]) {
val exp = Expr(PlusOp)
exp.bo(1,2)(plus)
}
}
The idea is to be able to state an operation that may be valid for many different types up front, without being tied to a type-specific operation. If I define an expression class generically, all is well
case class Expr[T <: BaseOps](bo: T = PlusOp)
However for my use case it is undesirable for Expr to to be paremeterized:
case class Expr(bo: BaseOps = PlusOp)
The following code fails without a generic Expr:
object App {
val plus = new Plus[Int] {
def apply(i: Int, i2: Int) = i + i2
}
def main(a: Array[String]) {
val exp = Expr(PlusOp)
exp.bo(1,2)(plus)
}
}
The error:
found : App.plus.type (with underlying type java.lang.Object with Plus[Int])
required: exp.bo.T[Int]
exp.bo(1,2)(plus)
This makes it seem as if the type information from the abstract type T[A] <: BinaryOp[A] is not being substantiated with the information in the subtype PlusOp, which overrides the abstract type as T[A] = Plus[A]. Is there any way to work around this without making Expr generic?
With "-Ydependent-method-types",
def Expr(_bo: BaseOps = PlusOp) = new BaseOps {
override type T[A] = _bo.T[A]
val bo: _bo.type = _bo
}
But, I don't know what this precisely means...