What I am trying to do :
trait BasicModel {
type U <: BasicModel
def -(that: U): BasicModel
...
}
class MatrixFactorizationModel(val W: DenseMatrix[Double], val b: Double) extends BasicModel {
type U = MatrixFactorizationModel
def -(that: MatrixFactorizationModel): MatrixFactorizationModel = new MatrixFactorizationModel(W + that.W, b - that.b)
...
}
abstract class SAG [T <: BasicModel#U : ClassTag] {
//type T <: BasicModel#U I also tried like that
def modelDerivative(idx: Index, cstDerivative: Double): T
def compute(): T = {
SumDerivative = SumDerivative - modelDerivative(idx, Hist(idx))
}
}
When compute is call I got this error :
type mismatch;
found : T
required: _129.U where val _129: T
SumDerivative = SumDerivative - modelDerivative(idx, Hist(idx))
I don't understand why this is not working because T is a BasicModel#U. Could someone explain me, and give me an alternative?
EDIT :
I also changed in SAG T <: BasicModel#u in T <: BasicModel and when I use T to change it in T#U :
abstract class SAG [T <: BasicModel : ClassTag] extends Optimizer {
def modelDerivative(idx: Index, cstDerivative: Double): T#U
...
}
But :
type mismatch;
found : T#U
required: _128.U where val _128: T#U
SumDerivative = SumDerivative - modelDerivative(idx, Hist(idx))
It's sort of like the type defined in BasicModel, U, is a member of an instance of BasicModel. It's like the difference between static/instance variables in Java. To match a type definition, you need the exact same type. If it were static, you couldn't override it in the subclass, MatrixFactorizationModel.
T <: BasicModel in SAG represents any T <: BasicModel#U (the parent #U) where that #U could be any subtype of BasicModel. Even though you might happen to have specified MatrixFactorizationModel wherever you instantiated an instance of SAG, the compiler doesn't know what specific T you have in this context, or that it's a subtype of the same U.
You might have better luck with something like trait BasicModel { def [T<:BasicModel]-(that:T):T }. It's a bit more verbose, and can be a real pain if you've got a lot of method signatures to type, but sometimes signatures like that work out better.
Related
I have a first trait like this :
trait FirstTrait[U] {
val myVal: U
}
And another one as follows :
trait SecondTrait[T <: firstTrait[U],U]
For the implementation I am doing :
case class FirstImpl(myVal: MyType) extends FirstTrait[MyType]
object SecondImpl extends SecondTrait[FirstImpl,MyType]
Is there a better way to do the same thing, I would like to simplify my implementation of the second trait like this if possible :
object SecondImpl extends SecondTrait[FirstImpl]
EDIT
I am using after both type in a function :
def func[T <: FirstTrait[U],U](myVal: T): U
When I use existential type, I have to explicit types or I get an "inferred type arguments [FirstImpl,Nothing] do not conform to method func" error.
So this is how I have to implement the function :
val myVal : MyType = MyType()
func[FirstImpl,MyType](FirstImpl(myVal))
Can anything simplify?
You can try existential type
trait FirstTrait[U] {
type _U = U
val myVal: U
}
trait SecondTrait[T <: FirstTrait[_]]
case class FirstImpl(myVal: MyType) extends FirstTrait[MyType]
object SecondImpl extends SecondTrait[FirstImpl]
def func[T <: FirstTrait[_]](myVal: T): myVal._U = ???
func(FirstImpl(myVal)): MyType
or
trait FirstTrait {
type U
val myVal: U
}
trait SecondTrait[T <: FirstTrait]
case class FirstImpl(myVal: MyType) extends FirstTrait { type U = MyType }
object SecondImpl extends SecondTrait[FirstImpl]
def func[T <: FirstTrait](myVal: T): myVal.U = ???
func(FirstImpl(myVal)): MyType
or
def func[T, U](myVal: T)(implicit ev: T <:< FirstTrait[U]): U = ???
def func[T <: FirstTrait[U],U](myVal: T): U
The problem is that the type of myVal doesn't mention U, so the compiler is failing to infer it simultaneously with T. If it inferred T first, it could get U from it, but it doesn't currently work this way.
However, T is actually useless here and it can be rewritten as
def func[U](myVal: FirstTrait[U]): U
You can already pass any subtype of FirstTrait[U] here and lose the source of the type inference problem.
If this is a simplified signature, a trick which can work is mentioning U in the parameter type even if it should be redundant:
def func[T <: FirstTrait[U], U](myVal: T with FirstTrait[U]): U
I encounter quite often the following issue in Scala :
Given a trait
trait Foo { def foo: String }
and a parameterized class
case class Bar[T <: Foo](t: T)
I'd like to write a method that work with a Bar without duplicating the type constraint, something like :
def doSth(bar: Bar[_]) = bar.t.foo
Unfortunately, it doesn't compile and I need to write :
def doSth[T <: Foo](bar: Bar[T]) = bar.t.foo
Why the compiler can't infer that if I have a Bar[_], the _ must be a Foo ?
Is there a workaround (abstract type will avoid the duplication, but it will add complexity to represent some constraints) ?
It seems as if
def doSth(bar: Bar[_]) = bar.t.foo
is essentially the same as
def doSth0(bar: Bar[X] forSome { type X }) = bar.t.foo
and type X is just completely unconstrained. In my opinion, the question should therefore be rather:
Why does the compiler allow something like Bar[X] forSome { type X } at all, even though X is not declared as subtype of Foo, whereas Bar requires the argument to be subtype of Foo?
I don't know an answer to that. Probably it again has something to do with java generics.
Workarounds
Given the trait and class
trait Foo { def foo: String }
case class Bar[T <: Foo](t: T)
the following two definitions work without an additional type parameter:
def doSth1(bar: Bar[X] forSome { type X <: Foo }) = bar.t.foo
def doSth2(bar: Bar[_ <: Foo]) = bar.t.foo
Another option would be to constrain the type of t in Bar itself:
case class Bar2[T <: Foo](t: T with Foo)
def doSth3(bar: Bar2[_]) = bar.t.foo
trait A {
type T
def test(t: T): Unit
}
case class B[S <: A](a: S, t : S#T) {
def test() = a.test(t) // Error: type mismatch;
// found : B.this.t.type (with underlying type S#T)
// required: B.this.a.T
}
Am I wrong to expect the above to compile? Can my code be fixed?
Compiler has not sufficient evidence that S#T can be used as argument for test in concrete instance.
Consider this hypotecical example for weakened scala compiler
trait A2 extends A{
type T <: AnyRef
}
class A3 extends A2{
override type T = Integer
def test(t: Integer): Unit = println(t * 2)
}
So B[A2] should accept instance of A3 along with anything that is <: AnyRef while A3 needs exactly Integer for its own test implementation
You can catch concrete type in the definition of B, to make sure what type will be used
case class B[S <: A, ST](a: S {type T = ST}, t: ST) {
def test() = a.test(t)
}
I could come up with encodings (removed the type parameters for simplification):
scala> :paste
// Entering paste mode (ctrl-D to finish)
def test0(a: A)(t : a.T) = a.test(t)
abstract class B{
val a: A
val t: a.T
def test = a.test(t)
}
// Exiting paste mode, now interpreting.
test0: (a: A)(t: a.T)Unit
defined class B
This on the other hand didn't work with case classes arguments (nor classes' for that matter).
One of the reasons your encoding wouldn't work:
scala> def test1(a: A)(t : A#T) = a.test(t)
<console>:12: error: type mismatch;
found : t.type (with underlying type A#T)
required: a.T
def test1(a: A)(t : A#T) = a.test(t)
The important part is required: a.T (versus A#T). The test method in A doesn't take any T, it takes T this.T, or in other words, the T belonging to one particular instance of A.
Instead of a type projection you can use the dependent type a.T:
trait A {
type T
def test(t: T): Unit
}
case class B[S <: A](a: S)(t : a.T) {
def test() = a.test(t)
}
I've been mulling over a design problem in a library I'm working on, and I realized that using existential types may allow me to change my design in a way that simplifies many parts of my library. However, I can't quite seem to get it to work.
It seems to me that myBuilder conforms to the type MultiSignalBuilder[E, R] forSome { type E[+X] >: Element[X] }, where Element[X] is MultiSignalElement[X], but the compiler says it does't. It seems to have to do the fact that E is a higher-kinded type. Why doesn't this work, and is there a way to fix it?
class MultiSignalElement[+T] {
}
abstract class MultiSignal[+T] {
type Element[+X] <: MultiSignalElement[X]
val element : Element[T]
def transform[R[+X] <: MultiSignal[X]](builder : MultiSignalBuilder[E, R] forSome { type E[+X] >: Element[X] }) : R[T] =
builder.buildNew(element)
}
abstract class MultiSignalBuilder[-E[+X] <: MultiSignalElement[X], +R[+X] <: MultiSignal[X]] {
def buildNew[T](element : E[T]) : R[T]
}
object myBuilder extends MultiSignalBuilder[MultiSignalElement, MultiSignal] {
def buildNew[T](e : MultiSignalElement[T]) = new MultiSignal[T]() {
type Element[+X] = MultiSignalElement[X]
val element = e
}
}
val multiSignal = new MultiSignal[Int] {
type Element[+X] = MultiSignalElement[X]
val element = new MultiSignalElement()
}
multiSignal.transform(myBuilder) //type error on this line
multiSignal.transform[MultiSignal](myBuilder) //type error on this line
Let do step-by-step analysis.
First we have
def transform[R](builder : MultiSignalBuilder[E, R] forSome { type E[+X] >: Element[X] }) : Unit = { }
Which is equivalent to statement : there exists
type E[+X] >: Element[X]
For which we can define
def transform[E[+X] >: Element[X], R[+_]](builder : MultiSignalBuilder[E, R] ) : Unit = { }
Here we have an error
Error:(7, 18) covariant type X occurs in contravariant position in
type [+X] >: MultiSignal.this.Element[X] of type E
This is something. You are expecting your mysterious existential covariant type should be a supertype of another covariant type. I think this is the first thing which is freaking the compiler. Lets change relation to subtyping
def transform[E[+X] <: Element[X], R[+_]](builder : MultiSignalBuilder[E, R] ) : Unit = { }
Now we have
Error:(7, 56) type arguments [E,R] do not conform to class
MultiSignalBuilder's type parameter bounds [-E[+X] <:
MultiSignalElement[X],+R[+X] <: MultiSignal[X]]
So we forgot to require subtyping of MultiSignal[X] out of R parameter.
Lets change it
def transform[E[+X] <: Element[X], R[+X] <: MultiSignal[X]](builder : MultiSignalBuilder[E, R] ) : Unit = { }
Now
multiSignal.transform[MultiSignalElement,MultiSignal](myBuilder)
Is succesfully compiled.
Finally we could get back to existential version
def transform[R[+X] <: MultiSignal[X]](builder : MultiSignalBuilder[E, R] forSome {type E[+X] <: Element[X]}) : Unit = { }
With which
multiSignal.transform[MultiSignal](myBuilder)
Is succesfully compiled.
Sadly
multiSignal.transform(myBuilder)
Still is not compiled. I think there is too much type relations to resolve for the compiler.
I am trying to define a method with the following signature:
def parse[T <: MyClass](statement: String): Try[List[T]] = {
My class is an abstract class:
sealed abstract class MyClass { }
case class MyClassChild(v: Int) extends MyClass
my parse method returns a Success(List[MyClassChild])
But the compiler complains with the following error:
Error:(124, 19) type mismatch;
found : scala.util.Try[List[parser.MyClass]]
required: scala.util.Try[List[T]]
Why doesn't scala.util.Try[List[parser.MyClass]] conform to scala.util.Try[List[T]], since T <: MyClass ?
Thank you
T should be >: MyClass and Try[List[T]] >: Try[List[MyClass]] (List and also Try is covariant, so it will work) to confirm return type - because your function can't return bigger type than declared (see Liskov substitution principle ):
scala> trait A { type MT; def aaa[T <: MT]: List[T] = null.asInstanceOf[List[MT]] }
<console>:7: error: type mismatch;
found : List[A.this.MT]
required: List[T]
scala> trait A { type MT; def aaa[T >: MT]: List[T] = null.asInstanceOf[List[MT]] }
defined trait A
If you want T <: MyClass - you should change return type to Try[List[MyClass]]:
scala> trait A { type MT; def aaa[T <: MT]: List[MT] = null.asInstanceOf[List[MT]] }
defined trait A
In other words, you can't "shrink" MyClass to T even theoretically because it's bigger by T <: MyClass definition. MyClass.asInstanceOf[T] will give you type cast error with probability > 0, it's like Any.asInstanceOf[String].