I have a use case similar to the situation following:
trait A {
implicit val x = "hello"
}
class B {
// somehow bring x into scope here???
def run(x: Int)(implicit y: String) = y + x
}
println((new B).run(3))
I understand that I need to bring x defined in the trait in the implicit scope of B. I've already tried the following:
# attempt 1 #
class B extends A { .... } /// doesn't work
# attempt 2 #
class B extends A {
val x1 = implicitly[String] /// doesn't work either
def run(x: Int)(implicit y: String) = y + x
}
Please explain what am I missing here (or, point me to relevant theory topic which I can study, fairly new to scala).
The value of 'implicit y' will be resolved in your println-line where it is not available. You are making the variable implicitly available within the body of the class, but resolution of implicit String is not needed there.
Implicit isn't magic; if you can't reach the implicit variable explicitly then so can't the compiler.
What problem are you really trying to solve?
Wrap your whole code in a object and extend trait A in class B :
object P {
trait A {
implicit val x = "hello"
}
class B extends A {
def run(y: Int) = y + x
}
def f = println(new B().run(3))
}
Output :
scala> P.f
3hello
Related
Because I didn't find a solution to my problem anywhere, I think I might be thinking into a very wrong direction.
Here's my problem:
I have a trait A and another trait B and companion objects AB1, AB2, AB3 and so on. The singleton objects extend trait A and the classes extend trait B. Many objects of those classes are in a list.
On these objects I want to use functions defined in the corresponding singleton object which take objects of the same class as the singleton object is.
This an example for the traits:
trait A {
def compare(firstB: B, secondB: B) : Int
}
trait B {}
And the companion objects:
class AB1(val variable: Int) extends B {}
object AB1 extends A {
def apply(list: List[Int]): Option[AB1] = {
if(list.foldLeft(0)(_ + _) < 10 && list.nonEmpty)
some(new AB1(list.head))
else
null
}
override def compare(ab11: AB1, ab12: AB1): Int = {
if(ab11 > ab12)
1
else if(ab11 > ab12)
-1
else
0
}
}
and
class AB2(val variable1: Int, val variable2: Int) extends B {}
object AB2 extends A {
def apply(list: List[Int]): Option[AB1] = {
if(list.foldLeft(0)(_ + _) < 20 && list.length >= 2)
some(new AB1(list.head, list.tail.head))
else
null
}
override def compare(ab21: AB2, ab22: AB2): Int = {
if(ab11 > ab12)
10
else if(ab11 > ab12)
-10
else
0
}
}
So I've already filtered the some objects and put the "real" objects into a list, let's call it bList. On every element of the list I want to call the compare function.
I think it would look something like this:
val bList: List[B]
val a = getA(bList.head) // getA should be a function that returns the companion object of a class
a.compare(bList.head, bList.tail.head)
On my way I encountered two problems:
b.getClass does not equal AB1.getClass when b is an object the class AB1. But this is not my main problem. I found a solution using String comparison, which really is not pretty, but for now, it works.
The compare function has to be defined in the trait, because otherwise it can't be casted on any singleton object that extends trait A. But I find no way to define the function with parameters of a variable type.
I really hope you can help me with this problem!
EDIT: Now I see that I've forgotten to mention something:
I think that I have to go a bit deeper into what I am trying to do to make you understand my problem:
I have a List[List[C]]. A List of those C's may be capable of creating an AB1 object with it but maybe AB2, or maybe AB3 and so on. So I have
val c: List[C] = (C1, C2, C4)
val aList: List[A] = (AB1, AB2, AB3, ...)
val bestB: B = (for{
element <- aList
} yield element (c)).flatten.head // Because the List aList is ordered: AB1 is the best case, AB2 the second best and so on.
I do that for every List[C] out of the List[List[C]]. So in the end I may have a List[B] = (AB3, AB1, AB2, AB1) (for example). From this list I want to get the "best" Bs according to the order of aList at first - then i get List[B] = (AB1, AB1). These two AB1's I want to compare and then put the "better" Element (according to the compare function of the corresponding object) or both into a new list. This is want I want to accomplish.
To be honest, I'm still confused with what is your root problem. But I will try to answer what I understood.
First, if you want to change the type of the arguments when overriding a function from a trait. Then, the answer is you can't! - Because that would break the Liskov Substitution Principle.
But you can achieve what you want with a Type Class .
trait B {}
trait BComparator[Bi <: B] {
def compare(firstB: Bi, secondB: Bi): Int
}
Now if you want a way to dynamically obtain the right instance of the BComparator for your sub-classes you could make those instances as implicit values in their companion objects.
class B1 extends B {}
object B1 {
implicit val B1Comparator: BComparator[B1] = new BComparator[B1] {
override def compare(firstB: B1, secondB: B2): Int = ???
}
}
Now, given b11 and b12 as instances of B1 you could just write
implicitly[BComparator[B1]].compare(b11, b12)
I think you need to use implicit Comparator:
trait B
case class AB1(variable: Int) extends B
case class AB2(variable1: Int, variable2: Int) extends B
implicit object AB1Comparator extends Comparator[AB1] {
override def compare(o1: AB1, o2: AB1): Int = java.lang.Integer.compare(o1.variable, o2.variable)
}
implicit object AB2Comparator extends Comparator[AB2] {
override def compare(o1: AB2, o2: AB2): Int = java.lang.Integer.compare(o1.variable1, o2.variable1) match {
case 0 => java.lang.Integer.compare(o1.variable2, o2.variable2)
case other => other
}
}
def compare[A](obj1: A, obj2: A)(implicit comparator: Comparator[A]) = {
comparator.compare(obj1, obj2)
}
val ab1List = List(AB1(1), AB1(2), AB1(3))
val ab1Compare = compare(ab1List.head, ab1List.tail.head)
val ab2List = List(AB2(1, 1), AB2(1, 1), AB2(1, 3))
val ab2Compare = compare(ab2List.head, ab2List.tail.head)
Or if you want to sort list you should use Ordering:
trait B
case class AB1(variable: Int) extends B
implicit object AB1Ordering extends Ordering[AB1] {
override def compare(o1: AB1, o2: AB1): Int = java.lang.Integer.compare(o1.variable, o2.variable)
}
val ab1List = List(AB1(1), AB1(2), AB1(3))
val ab1ListSorted = ab1List.sorted
I'm trying to make a typeclass that depends on user input. Imagine we have some case objects:
sealed trait H
case object Ha extends H
case object Hb extends H
and the type class:
trait Foo[A] {
def bar: String
}
object Foo {
def bar[A : Foo] = implicitly[Foo[A]].bar
implicit object FooA extends Foo[Ha.type] {
override def bar: String = "A"
}
implicit object FooB extends Foo[Hb.type] {
override def bar: String = "B"
}
}
While I found a working solution using a match:
variableComingFromMainArgs match {
case "a" => Foo.bar[Ha.type] _
case "b" => Foo.bar[Hb.type] _
}
I remember that we have abstract types in Scala, so I could change my case class into:
sealed trait H {
type T <: H
}
case object Ha extends H {
type T = this.type
}
case object Hb extends H {
type T = this.type
}
Now, when depending on user input to the program, I could do something like
val variable = Ha
println(Foo.bar[variable.T])
However, for some reason this doesn't work the and the error is not very useful for me:
error: could not find implicit value for evidence parameter of type Foo[variable.T]
println(Foo.bar[variable.T])
Any ideas if this can be overcome, if not, why?
Thanks.
Implicits are compile time constructs so in principle they cannot depend on user input directly (programmer can wire it for example with pattern matching as you did).
Consider the following code. It compiles and works as intended:
trait H {
type A
}
case object Ha extends H {
override type A = Int
}
case object Hb extends H {
override type A = Long
}
trait Adder[T] {
def add(a: T, b: T): T
}
implicit object IntAdder extends Adder[Int] {
override def add(a: Int, b: Int): Int = a + b
}
implicit object LongAdder extends Adder[Long] {
override def add(a: Long, b: Long): Long = a + b
}
def addWithAdder(input: H)(a: input.A, b: input.A)(implicit ev: Adder[input.A]): input.A = ev.add(a, b)
val x: Int = addWithAdder(Ha)(3, 4)
val y: Long = addWithAdder(Hb)(3, 4)
Let's focus on addWithAdder method. Thanks to path dependent types compiler can choose correct implicit for this task. But still this method is basically the same as the following:
def add[T](a: T, b: T)(implicit ev: Adder[T]) = ev.add(a, b)
The only advantage first one can have is that you can provide all instances yourself and stop the user of your code to add own types (when H is sealed and all implementations are final).
If I have the following code:
trait MyTrait {
val x: Int
}
def f(_x: Int) = new MyTrait {
val x = _x
}
If I were to define my function as follows:
def f(x: Int) = new MyTrait {
val x = x
}
This would be incorrect as val x is just referring to itself. Is there a way I can avoid having to use a different name for 'x' when I want to refer to something in the outer scope?
You can, but only if the outer scope x is a member of enclosing type, not a method parameter or a local variable:
class MyOuter(val x: Int) {
def f() = new MyTrait {
val x = MyOuter.this.x
}
Not really: in the scope of MyTrait, x refers to the field. However, you have the option to wrap parameter into some other name before you enter that scope:
def f(x: Int) = {
val xn = x
new MyTrait {
val x = xn
}
}
Well, in this particular case, you could write something like this:
def f(x: Int) = {
class Foo(val x: Int = x) extends MyTrait
new Foo
}
Not sure what exactly it makes better over just renaming x to y though ...
I have a trait and a case class implementing it. One of the features of the trait that the implementations override is a default value. I can't find a good way to access this default value from a class that is parametrized by a specific implementation of that trait.
This is minimal code, so it doesn't really demonstrate the motivation anymore, but it does demonstrate the error:
import scala.language.implicitConversions
trait Distance[T] {
val Zero: T
def +( that: T ): T
}
case class DoubleDistance( val v: Double ) extends Distance[DoubleDistance] {
val Zero = DoubleDistance( 0.0 )
def +( that: DoubleDistance ) = DoubleDistance( v + that.v )
}
object DistanceImplicits {
implicit def DoubleToDistance( v: Double ) = new DoubleDistance( v )
}
class User[T<:Distance[T]] {
val default: T = T.Zero // This line gives me a compilation error
}
The error I get is
not found: value T
When I needed to construct an Array[T] inside my User class I could get that to work by adding implicit typetag:ClassTag[T] to my arguments, but that doesn't seem to have any effect here.
First, why this doesn't work: consider a different implementation of Distance.
case class DoubleDistance1(val v: Double) extends Distance[DoubleDistance1] {
val Zero = this
def +(that: DoubleDistance1) = ??? // doesn't matter
}
What would you expect DoubleDistance1.Zero to mean? You can make it work using a "type class":
trait DistanceOps[T] {
val zero: T
def add(d1: T, d2: T): T
}
// just to let you write distance1 + distance2
implicit class RichDistance[T](d: T)(implicit ops: DistanceOps[T]) {
def +(other: T) = ops.add(d, other)
}
case class DoubleDistance(v: Double)
object DoubleDistance {
implicit object DoubleDistanceOps extends DistanceOps[DoubleDistance] {
val zero = DoubleDistance(0.0)
def add(d1: DoubleDistance, d2: DoubleDistance) = DoubleDistance(d1.v + d2.v)
}
}
// how to use
class User[T](implicit ops: DistanceOps[T]) {
val default: T = ops.zero
}
This looks like a classic use case for the type class pattern. Rather than associating an instance of the Distance trait with each value of interest, you associate one with each type of interest:
trait Distance[T] {
val Zero: T
def +( a: T, b: T ): T
}
implicit object DoubleDistance extends Distance[Double] {
val Zero = 0.0
def +( a: Double, b: Double ) = a + b
}
class User[T : Distance] {
val default: T = implicitly[Distance[T]].Zero
}
Where is that Zero supposed to come from? Are you looking to do something like this?
class User[T<:Distance[T]] {
self:Distance[T] =>
val default: T = Zero
}
I'm trying to compile the following code, but the last line does not compile:
class SuperContainer (
val shapeSets: Set[MyContainer[Shape]] = Set.empty[MyContainer[Shape]]) {
def addAct(el: MyContainer[Shape]) = {
new SuperContainer(shapeSets + el)
}
}
class MyContainer[A](val ls: Set[A] = Set.empty[A]) {
def addElement(el: A) = {
new MyContainer(ls + el)
}
}
abstract class Shape
case class Circle(radius: Int) extends Shape {
override def toString = "Circle(" + radius + ")"
}
case class Square(s: Int) extends Shape {
override def toString = "Square(" + s + ")"
}
object MyContainer {
def main(args: Array[String]) {
//Circle Container
val myc1 = new MyContainer[Circle]()
val myc11 = myc1.addElement(new Circle(6))
//Square Container
val myc2 = new MyContainer[Square]()
val myc21 = myc2.addElement(new Square(6))
val scont = new SuperContainer
scont.addAct(myc11) //does not compile
}
}
Scala compiler suggests me to use +A in MyContainer class definition, but by doing that, other compile errors occur. Am I doing something wrong or this is just a Scala limitation? Is there any way to overcome this problem?
In order to achieve what you want, MyContainer has to be covariant:
class MyContainer[+A](val ls: Set[A] = Set.empty[A]) // ...
Now, your definition of addElement will cause an error, since A appears in contravariant position (as a function argument in this case). You will have to adapt your signature as follows:
def addElement[B >: A](el: B): MyContainer[B]
This makes sense if you think of it: If you have a Container[Circle] (which can be seen as a Container[Shape] due to covariance) and you add a Shape, you have a Container[Shape] at the end and not a Container[Circle].
The implementation of addElement will not change.
Further, you cannot make Set[A] available outside the class (i.e. you have to remove the val), since Set[A] is not covariant. If you want to access elements, you'll have to add additional methods to query the set.
class MyContainer[+A](ls: Set[A] = Set.empty[A]) // ...
UPDATE
This is to explain clearer, why Set[A] cannot be part of MyContainer[+A]'s public API. Say we have:
class A
class B extends A
Imagine the following:
val x: MyContainer[A] = new MyContainer[B]
We can do that due to the covariance. However, if we could call now:
val s = x.ls // get internal set
We expect s to be of type Set[A]. However, the internal Set of x is a Set[B] which is not a Set[A]. Therefore this is not correctly typed.