What I need is, let say, I have a List trait, and Value trait, and special lists store special Value types. I tried this, but line.value doesn't exist, and the reason is, it looks like prepend's type parameter is not the actual SingleValue class, but it is still a template. But why? thanks
sealed trait Value
case class SingleValue(value: Int) extends Value
case class DoubleValue(value1: Int, value2: Int) extends Value
trait List1 {
def prepend[B <: Value](value: B): Int
}
case class SingleList1 extends List1 {
def prepend[SingleValue](line: SingleValue): Int = {
line.value
}
}
SingleValue in def prepend[SingleValue](line: SingleValue) is a type parameter, not a concrete type.
Like when you wrote def prepend[B <: Value](value: B): Int, you used B as a variable def prepend[SingleValue] has exactly the same meaning (except that variable name is different, but that's immaterial).
It is not very clear from your question what exactly you are trying to do here ... but, if I am guessing correctly, you want to parametrize the class, not the method:
trait List1[B <: Value] {
def prepend(b: B): Int
}
class SingleList extends List1[SingleValue] {
def prepend(sv: SingleValue) = sv.value
}
Update So, if you want your List1 to be covariant, as you mentioned in the comment, that won't work: if it did, then SingleList would be a subclass of List1[Value], and therefore prepend would have to work with any Value, not just SingleValue, and it doesn't know how.
What you could do in that case, is define the specialized prepend method "on the side" and associate it with List1 via an implicit conversion:
trait Lis1[+B <: Value]
object List1Ops {
implicit class SVL[T <: SingleValue](val l: List1[T]) extends AnyVal {
def prepend(v: T) = v.value
}
}
This let's you do both things like:
val svl = new List1[SingleValue]{}
println(svl.prepend(new SingleValue))
and
val l: List1[Value] = new List1[SingleValue]{} // still covariant
Is that what you are after?
Related
I need to provide type class instances for a bunch of case classes all derived from a single trait, but as far as I understand Scala compiler expects an instance for a specific class and doesn't go up the inheritance hierarchy. So this code:
trait Base
sealed trait Child extends Base
case class Concrete() extends Child
trait Printable[A] {
def print(value: A): String
}
object WtfTrait {
def print[A](x: A)(implicit ev: Printable[A]) = {
println(ev.print(x))
}
implicit val printableBase = new Printable[Base] {
override def print(value: Base): String = value.toString
}
val x = Concrete()
print(x)
}
doesn't compile with an error reading could not find implicit value for parameter ev: Printable[Impl]. Is there a way to define a single type class instance for the base trait and avoid repitition maybe by using Shapeless or something.
Guess you mean Printable[Concrete] (that's to say a Show typeclass instance).
Need to update to printableBase definition as bellow:
trait Base
sealed trait Child extends Base
case class Concrete() extends Child
trait Printable[A] {
def print(value: A): String
}
object WtfTrait {
def print[A](x: A)(implicit ev: Printable[A]) = {
println(ev.print(x))
}
// HERE
implicit def printableBase[T <: Base] = new Printable[T] {
override def print(value: T): String = value.toString
}
val x = Concrete()
print(x)
}
Printable can be made contravariant by adding a - sign:
trait Printable[-A]
This makes Printable[X] a subtype of Printable[Y] if Y is a subtype of X. In particular, Printable[Base] is a subtype of Printable[Concrete] and can be used when the compiler looks for an implicit of that type.
I have a trait
trait Weight {
def getWeight: Int
}
Multiple classes inherits it, example:
case class Test(n: Int) extends Weight {
override def getWeight: Int = n
}
Now i want to add sorting ability to all Weight subclasses. I added Ordered to Weight:
trait Weight extends Ordered[Weight] {
def getWeight: Int
override def compare(that: Weight): Int = this.getWeight.compareTo(that.getWeight)
}
Try sorting:
val seq = Seq(Test(1), Test(4), Test(3), Test(2))
seq.sorted // error
And it's not compiles:
Error:(74, 6) diverging implicit expansion for type
scala.math.Ordering[A$A254.this.Test] starting with method $conforms
in object Predef seq.sorted;}
^
Whats i am doing wrong?
Another solution a bit different than mdm. Since sorted takes an implicit of Ordering, you can do the following:
seq.sorted(Ordering[Weight])
Your solution does not work because Ordered[T] is invariant in T, meaning that Ordered[Weight] has no relationship with Ordered[A]. You would need to specify that in the sub-classes.
You could use an implicit Ordering rather than an Ordered.
trait Weight{
def getWeight : Int
}
object Weight{
implicit def ordering[T <: Weight] : Ordering[T] = Ordering.by(w => w.getWeight)
}
case class A(w : Int) extends Weight{
def getWeight = w
}
case class B(w : Int) extends Weight{
def getWeight = w
}
import Weight._
Seq(A(1),B(2),B(0),A(3),A(-3)).sorted
Will result in:
List(A(-3), B(0), A(1), B(2), A(3))
Note that this solution relies on an Ordering[Int] to be available (which is, by default).
I want to write a generic class that takes a nested type. The outer type (I) has to extend Iterable, and the inner type (M) can be anything.
Here is the example I have:
// The outer type here is I and the inner type is M
class GenericDistributor[I <: Iterable[M], M] {
def map(input: I): Unit = {
input.foreach(item => {
//do some stuff
})
}
}
class IntegerGroup(id: Int, items: Set[Int]) extends Iterable[Int] {
override def iterator: Iterator[Int] = items.iterator
}
object IntegerGroupDistributor extends GenericDistributor[IntegerGroup, Int]
val integerGroup = new IntegerGroup(1, Set(1,2,3))
IntegerGroupDistributor.map(integerGroup)
The problem is that I have to explicitly define the inner type M in the GenericDistributor class which I do not want to. Is there a way for Scala to automatically infer the inner type given the outer type?
EDIT
According to the comment of #Arioch. I tried duck types and that seems to fix my problem but still I feel there should be neater way.
class GenericDistributor[I <: {type M; def iterator: Iterator[M]}] {
def map(input: I): Unit = {
val it: Iterator[M] = input.iterator
it.foreach(println)
}
}
class IntegerGroup(id: Int, items: Set[Int]) extends Iterable[Int] {
type M = Int
override def iterator: Iterator[Int] = items.iterator
}
object IntegerGroupDistributor extends GenericDistributor[IntegerGroup]
If you don't need to use any custom methods of type I, your external class need only be parameterized on M. The Iterator[M] does not needed to be added separately since you already have all you need to define it from M.
class GenericDistributor[M] {
type I = Iterable[M]
def map(input: I): Unit = {
input.foreach(item => {
//do some stuff
})
}
}
If you only want a single type parameter there are two options:
(1) State that you do not care about the iterator's type
class GenericDistributor[I <: Iterable[_]]
(2) Use an implicit to store the inner type
class GenericDistributor[I : IterableInfo]
// or (equivalently)
class GenericDistributor[I]()(implicit i: IterableInfo[I])
trait IterableInfo[I] {
type Element
}
object IterableInfo {
implicit def forIterable[I <: Iterable[M], M]: IterableInfo[I] { type Element = M } = ...
}
The last option allows you to shape your code in a lot of different ways. You could add methods to IterableInfo, you could add type members, you could add a restriction of Iterable to the I type parameter.
Given a polymorphic function, how to match the polymorphic argument and return a value of the same type without resorting to explicit casts?
sealed trait Data
case class DString(s: String) extends Data
case class DInt(n: Int) extends Data
def double[D <: Data](d: D): D = d match {
case DString(s) => DString(s ++ s)
case DInt(n) => DInt(n + n)
}
This produces type mismatches (found DString/DInt, required D).
Why does the type system not accept this when the input type clearly equals the output type?
This may be a legitimate place to use method overloading:
def double(ds: DString) = DString(ds.s ++ ds.s)
def double(di: DInt) = DInt(di.n + di.n)
You can also use type classes:
abstract class DataDoubler[A <: Data] {
def double(a: A): A
}
implicit object DStringDoubler extends DataDoubler[DString] {
def double(ds: DString) = DString(ds.s ++ ds.s)
}
implicit object DIntDoubler extends DataDoubler[DInt] {
def double(di: DInt) = DInt(di.n + di.n)
}
def double[A <: Data](a: A)(implicit dd: DataDoubler[A]): A = dd.double(a)
This seems like a reformulation of a problem that pops up time and again on StackOverflow, which is usually solved using F-bounded polymorphism. The only difference is that you want to preserve the type you're working on in a function that's not defined inside the trait.
So, what I'd do is move that double method inside the Data trait and use an abstract type member:
sealed trait Data {
type Self <: Data
def double: Self
}
case class DString(s: String) extends Data {
type Self = DString
def double = DString(s ++ s)
}
case class DInt(n: Int) extends Data {
type Self = DInt
def double = DInt(n + n)
}
Otherwise, I'm not aware of a solution.
I need a way to enforce a method in an abstract class to have a return type of the concrete class of the object it is called on. The most common example is a copy() method, and I'm currently using an approach based on abstract types:
abstract class A(id: Int) {
type Self <: A
def copy(newId: Int): Self
}
class B(id: Int, x: String) extends A(id) {
type Self = B
def copy(newId: Int) = new B(newId, x)
}
class C(id: Int, y: String, z: String) extends A(id) {
type Self = C
def copy(newId: Int) = new C(newId, y, z)
}
I already saw many approaches, including the ones in this great answer. However, none of them really forces a implementation to return its own type. For example, the following classes would be valid:
class D(id: Int, w: String) extends A(id) {
type Self = A
def copy(newId: Int) = new D(newId, w) // returns an A
}
class E(id: Int, v: String) extends A(id) {
type Self = B
def copy(newId: Int) = new B(newId, "")
}
The fact that I can do that causes that, if I am doing copies of objects of which the only information I have is that they are of a given subclass of A's:
// type error: Seq[A] is not a Seq[CA]!
def createCopies[CA <: A](seq: Seq[CA]): Seq[CA] = seq.map(_.copy(genNewId()))
Is there a better, type-safe way I can do that?
EDIT: If possible, I would like to keep the ability to create arbitrarily deep hierarchies of abstract classes. That is, in the previous example, I'm expecting to be able to create an abstract class A2 that extends A, and then proceed to create A2's concrete subclasses. However, if that simplifies the problem (as it's the case with abstract types), I do not need to further extend already concrete classes.
The only solution I could think of was this one:
trait CanCopy[T <: CanCopy[T]] { self: T =>
type Self >: self.type <: T
def copy(newId: Int): Self
}
abstract class A(id: Int) { self:CanCopy[_] =>
def copy(newId: Int): Self
}
The following would compile:
class B(id: Int, x: String) extends A(id) with CanCopy[B] {
type Self = B
def copy(newId: Int) = new B(newId, x)
}
class C(id: Int, y: String, z: String) extends A(id) with CanCopy[C] {
type Self = C
def copy(newId: Int) = new C(newId, y, z)
}
The following would not compile:
class D(id: Int, w: String) extends A(id) with CanCopy[D] {
type Self = A
def copy(newId: Int) = new D(newId, w) // returns an A
}
class E(id: Int, v: String) extends A(id) with CanCopy[E] {
type Self = B
def copy(newId: Int) = new B(newId, "")
}
Edit
I actually forgot to remove the copy method. This might be a bit more generic:
trait StrictSelf[T <: StrictSelf[T]] { self: T =>
type Self >: self.type <: T
}
abstract class A(id: Int) { self:StrictSelf[_] =>
def copy(newId:Int):Self
}
Do not force the type bound on the declaration side, unless you need that bound within the definition of A itelf. The following is sufficient:
abstract class A(id: Int) {
type Self
def copy(newId: Int): Self
}
Now force the Self type on the use site:
def genNewId(): Int = ???
def createCopies[A1 <: A { type Self = A1 }](seq: Seq[A1]): Seq[A1] =
seq.map(_.copy(genNewId()))
I don't think it's possible in scala to do what you want.
If I were to:
class Base { type A }
class Other extends Base
class Sub extends Other
Now... we want type A to refer to "the type of the subclass."
You can see that from the context of Base, it's not particularly clear (from the compiler's perspective) what the specific "type of the subclass" means, nevermind what the syntax would be to refer to it in the parent. In Other it would mean an instance of Other, but in Sub it might mean an instance of Sub? Would it be OK to define an implementation of your method returning an Other in Other but not in Sub? If there are two methods returning A's, and one is implemented in Other and the other in Sub, does that mean the type defined in Base has two different meanings/bounds/restrictions at the same time? Then what happens if A is referred to outside of these classes?
The closest thing we have is this.type. I'm not sure if it would be theoretically possible to relax the meaning of this.type (or provide a more relaxed version), but as implemented it means a very specific type, so specific that the only return value satisfying def foo:this.type is this itself.
I'd like to be able to do what you suggest, but I'm not sure how it would work. Let's imagine that this.type meant... something more general. What would it be? We can't just say "any of the defined types of this," because you wouldn't want class Subclass with MyTrait{type A=MyTrait} to be valid. We could say "a type satisfying all of the types of this," but it gets confusing when someone writes val a = new Foo with SomeOtherMixin... and I'm still not sure it could be defined in a way that would enable an implementation of both Other and Sub defined above.
We're sort-of trying to mix static and dynamically defined types.
In Scala, when you say class B { type T <: B }, T is specific to the instance, and B is static (I'm using that word in the sense of static methods in java). You could say class Foo(o:Object){type T = o.type}, and T would be different for every instance.... but when you write type T=Foo, Foo is the statically specified type of the class. You could just as well have had an object Bar, and had referred to some Bar.AnotherType. The AnotherType, since it's essentially "static," (though not really called "static" in Scala), doesn't participate in inheritance in Foo.
However, none of them really forces a implementation to return its own type. For example, the following classes would be valid.
But isn't it normal? Otherwise it would mean that you could not merely extend A to add a new method by example, as it would automatically break the contract that you are trying to create (that is, the new class's copy would not return an instance of this class, but of A).
The very fact of being able to have a perfectly fine class A that breaks as soon as you extend it as class B feels wrong to me.
But to be honest I have trouble putting words on the problems it causes.
UPDATE: After thinking a bit more about this, I think this could be sound if the type check ("return type == most-derived class") was made only in concrete classes and never on abstract classes or traits.
I am not aware of any way to encode that in the scala type system though.
The fact that I can do that causes that, if I am doing copies of objects of which the only information I have is that they are of a given subclass of A's
Why can't you just return a Seq[Ca#Self] ? By example, with this change passing a list of B to createCopies will as expected return a Seq[B] (and not just a Seq[A]:
scala> def createCopies[CA <: A](seq: Seq[CA]): Seq[CA#Self] = seq.map(_.copy(123))
createCopies: [CA <: A](seq: Seq[CA])Seq[CA#Self]
scala> val bs = List[B]( new B(1, "one"), new B(2, "two"))
bs: List[B] = List(B#29b9ab6c, B#5ca554da)
scala> val bs2: Seq[B] = createCopies(bs)
bs2: Seq[B] = List(B#92334e4, B#6665696b)