Scala Upper type bounds implicitly? - scala

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

Type bounds constraints restrictions in Higher Kinds when extending a trait

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.

How to implement scala generic function that takes subtype of parameterized traits and returns it

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!

How to avoid duplication of type constraint in scala

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

Define a type constructor to build a type lambda (partially applied type)

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)

Scala generic type in trait

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.