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
Related
Let's set up issue conditions
trait Bound
trait Bound2 extends Bound
trait T1[B <: Bound]
trait T2[B <: Bound2] extends T1[B]
trait WrapperT1[Tz[B2 <: Bound] <: T1[B2]]
This code compile without problem, issue comes when trying to extend WrapperT1
trait WrapperT2[Tz[B2 <: Bound2] <: T2[B2]] extends WrapperT1[T2]
// Compilator error
kinds of the type arguments (T2) do not conform to the expected kinds of the type parameters (type Tz) in trait WrapperT1.
[error] ex.T2's type parameters do not match type Tz's expected parameters:
[error] type B's bounds <: Bound2 are stricter than type B2's declared bounds <: ex.Bound
[error] trait WrapperT2[Tz[B2 <: Bound2] <: T2[B2]] extends WrapperT1[T2]
Yes B2 <: Bound2 is stricter than B2 <: Bound but i'm not understanding why the compilator complains for this reason and i would be grateful to know more about it.
Potential solution but does it has some drawbacks ?
trait Bound
trait Bound2 extends Bound
trait T1[B] {
implicit val ev: B <:< Bound
}
trait T2[B] extends T1[B] {
// this is possible thank's to covariance of class `<:<[-From, +To]` if i'm not wrong
implicit val ev: B <:< Bound2
}
trait WrapperT1[Tz[B2] <: T1[B2]]
// Compiles
trait WrapperT2[Tz[B2] <: T2[B2]] extends WrapperT1[Tz]
This looks nice and we keep the compilation checks about B2 generic type but is there any inconveniant using it ?
To understand why the compiler complains, let's look at this piece of code (which is the same as your code, but with different names)
trait Show[A <: AnyRef] {
def show(a: A): Unit
}
trait ShowString[S <: CharSequence] extends Show[S] {
def show(s: S): Unit = println(s)
}
trait Wrapper1[S[A <: AnyRef] <: Show[A]] {
def show[A <: AnyRef](a: A)(implicit show: S[A]): Unit = show.show(a)
}
trait Wrapper2[S[C <: CharSequence] <: ShowString[C]] extends Wrapper1[S]
Here, too, the compiler emits the error type C's bounds <: CharSequence are stricter than type A's declared bounds <: AnyRef, but let's pretend you somehow get it to compile here. That would mean if someone wanted to use your wrapper class to print, say, a list, they wouldn't be able to do that, meaning that your wrapper class would be basically useless.
val w2: Wrapper[ShowString] = ???
w2.show(List(1, 2))
//Error: could not find implicit value for parameter show: ShowString[List[Int]]
In this case, it's just that the implicit isn't found. However, if you have a method in wrapper that accepts a S[_] (or Tz[_], from your example) and you try to shoehorn an object of the wrong type into your show method, you could get a runtime exception.
It fails for the same reason you can't do this
trait T1[A] {
def process(a: A): Unit
}
trait T2 extends T1[Int] {
def process(i: Int): Unit = ???
}
val t2: T2 = ???
t2.process("not an int")
T2 is just not equipped to handle anything that is not an Int, and the same applies here.
I don't need any information about type T on runtime so I think ClassTag is useless here.
I just need to return in my function the same type I've taken as an argument.
class MyClass[T] extends A with B[T] with C with D
trait A
trait B[T] {
def usefulMethod: Unit = println("B")
}
trait C
trait D {
def usefulMethodToo: Unit = println("D")
}
I've tried to implement my function like this but compiler infers Nothing
def helper[T, A <: B[T] with D](x: A): A = {
x.usefulMethod
x.usefulMethodToo
x
}
helper(new MyClass[Int])
Can it be inferred by compiler somehow?
The problem is that it can't infer T, but in this (maybe oversimplified?) case you don't actually need it:
def helper[A <: B[_] with D](x: A): A = {
x.usefulMethod
x.usefulMethodToo
x
}
This workaround works too:
def helper[T, A <: B[T] with D](x: A with B[T]): A = {
x.usefulMethod
x.usefulMethodToo
x
}
I'm not 100% sure, but I guess that in your particular case MyClass has also a type, maybe that is the reason why compiler can not infer it.
I would try next:
def helper[T, A[_] <: B[_] with D](x: A[T]): A[T] = {
x.usefulMethod
x.usefulMethodToo
x
}
Unfortunately this won't work for case like class IntMyClass extends B[Int] with D - but I don't have better ideas for now.
Hope this helps!
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
I am having problems defining a type constructor to do away with the horrible type-lambda approach to partial type application in Scala. Given:
trait Sys[S <: Sys[S]]
trait Expr[S <: Sys[S], +A] {
def value: A
}
import reflect.ClassTag
trait Proc[S <: Sys[S]] {
def attribute[A[~ <: Sys[~]]](key: String)
(implicit tag: ClassTag[A[S]]): Option[A[S]]
}
Let's say I have this method:
def name[S <: Sys[S]](p: Proc[S]): String =
p.attribute[({type A[~ <: Sys[~]] = Expr[~, String]})#A]("name")
.fold("<unnamed>")(_.value)
I want to define it rather like this:
def name[S <: Sys[S]](p: Proc[S]): String =
p.attribute[XXX[String]]("name").fold("<unnamed>")(_.value)
The question is: How can I define the type constructor XXX[A]?
My idea was this:
type XXX[A] = ({type Ex[S <: Sys[S]] = Expr[S, A]})#Ex
But it only produces
<console>:52: error: type Ex takes type parameters
type XXX[A] = ({type Ex[S <: Sys[S]] = Expr[S, A]})#Ex
^
I can't seem to find a solution other than staying with a type-projection, only shorter:
trait Ex[A] { type L[S <: Sys[S]] = Expr[S, A] }
def name[S <: Sys[S]](p: Proc[S]): String =
p.attribute[Ex[String]#L]("name").fold("<unnamed>")(_.value)
This is still not what I want. Can I get rid of the type-projection altogether?
A second idea is to provide an extension method:
implicit class RichProc[S <: Sys[S]](val `this`: Proc[S]) extends AnyVal {
def attrExpr[A](key: String)
(implicit tag: ClassTag[Expr[S, A]]): Option[Expr[S, A]] =
`this`.attribute[({type Ex[~ <: Sys[~]] = Expr[~, A]})#Ex](key)
}
def name[S <: Sys[S]](p: Proc[S]): String =
p.attrExpr[String]("name").fold("<unnamed>")(_.value)
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.