Accessing class-level values of type parameters in Scala - scala

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
}

Related

Covariant data structure with numeric types

How do I create a covariant data structure containing numeric data types?
In scala I can create a covariant data structure, with a hierarchy of type parameters:
abstract class Car[+T] {
def value: T
}
class RaceCar extends Car[RacingWheel] {
def value: RacingWheel = new RacingWheel
}
class NormalCar extends Car[BoringWheel] {
def value: BoringWheel = new BoringWheel
}
class Wheel
case class RacingWheel() extends Wheel
case class BoringWheel() extends Wheel
object Car {
def main(args: Array[String]): Unit = {
val rCar: Car[Wheel] = new RaceCar
val nCar: Car[Wheel] = new NormalCar
val listCars: List[Car[Wheel]] = List(rCar, nCar)
}
}
However, when I replace the Wheel's with numeric data types I run into a problem, because the numeric data types do not have a common type parent other than AnyVal:
abstract class Item[+N] {
def value: N
}
class IntItem(x : Int) extends Item[Int] {
override def value: Int = x
}
class DoubleItem(x : Double) extends Item[Double] {
override def value: Double = x
}
object Item {
def main(args: Array[String]): Unit = {
// ERROR Expression of IntItem does not conform to expected type Item[Number]
val iItem: Item[Number] = new IntItem(10)
// ERROR Expression of DoubleItem does not conform to expected type Item[Number]
val dItem: Item[Number] = new DoubleItem(10.9)
val l: List[Item[Number]] = List(iItem, dItem)
// ERROR: Expression of IntItem does not conform to expected type Item[Double]
val iItem2: Item[Double] = new IntItem(10)
val dItem2: Item[Double] = new DoubleItem(10.9)
val l2: List[Item[Double]] = List(iItem2, dItem2)
}
}
Outside of the covariant data structure I get mixed results:
object NumberMain {
val a : Int = 5
val b : Double = 10.0
val list : List[Number] = List(a, b)
// works, so Number must be related to Int and Double, right?
val x : Number = 5
// ERROR: Expression of type Number doesn't conform to expected type Int
val y : Int = x
// does not work, so Number is not related to Int and Double after all...
}
What changes do I have to make to the Item data structure? Can I tell it that all items can be seen as of type numeric?
In Scala, Int and Double do not share hierarchy with a common Number class. The Typeclass pattern can help you in these cases to define extra features for types without a common supertype.
trait MyNumber[A]
implicit case object IntMyNumber extends MyNumber[Int]
implicit case object DoubleMyNumber extends MyNumber[Double]
class Item[N](x: N)(implicit n: MyNumber[N]) {
def value: N = x
}
The Item class constructor now expects a second group of parameters labeled with the implicit keyword. If you call the method without this group of parameters, the compiler tries to find it (an instance of MyNumber) from variables or imports also labeled with implicit (Where does Scala look for implicits?).
We're just defining here that Int and Double implements MyNumber, but it doesn't do anything. We can write then the class as:
class Item[N : MyNumber](x: N) {
def value: N = x
}
And it works as we expected:
val iItem = new Item(1)
val dItem = new Item(1.0)
scala> iItem.value
res1: Int = 1
scala> dItem.value
res2: Double = 1.0
If we try to build an item of anything without an instance of MyNumber, the compiler throws an error:
val sItem = new Item("S")
error: could not find implicit value for evidence parameter of type MyNumber[String]
If you want MyNumber to be any numeric, Scala implements a Numeric typeclass.
Edit
If you want to add some features to the typeclass that are different for each number, you can do:
trait MyNumber[A] {
def doStuff(a: A): Unit
}
implicit case object IntMyNumber extends MyNumber[Int] {
def doStuff(number: Int): Unit = println("Int")
}
implicit case object DoubleMyNumber extends MyNumber[Double] {
def doStuff(number: Double): Unit = println("Double")
}
case class Item[+N](x: N)(implicit myNumber: MyNumber[N]) {
def value: N = x
def doStuff = myNumber.doStuff(x)
}

Scala Typeclasses

I'm trying to implement simple type class pattern. It suppose to work similarly to scalaz's typeclasses. Unfortunately I can't get it to work. I have trait Str
trait Str[T] {
def str(t: T): String
}
object Str {
def apply[T](implicit instance: Str[T]) : Str[T] = instance
}
And in my and implicit instance of it.
object Temp extends App {
implicit val intStr = new Str[Int] {
def str(i: Int) = i.toString
}
1.str //error: value str is not a member of Int
}
I would appreciate any insight.
Everything you can do now is
Str[Int].str(1)
to use 1.str you need to introduce implicit conversion.
You can for example use this approach:
implicit class StrOps[A](val self: A) extends AnyVal {
def str(implicit S: Str[A]) = S.str(self)
}
Which gives:
scala> 1.str
res2: String = 1

how to copy instance and override value field declared in trait

Suppose I have some abstract value field defined in a trait:
trait Base {
val toBeOverride: String
}
case class Impl(other:Int) extends Base {
override val toBeOverride = "some value"
}
How can I write a function that I can easily get a cloned instance only overriding the toBeOverride value, like this:
// copy only available to case class instance
// v does not have method 'copy'
def overrideBaseValue[T <: Base](v: Base) =
v.copy(toBeOverride = "prefix" + v.toBeOverride)
?
Edit
#som-snytt, I don't think this is a duplicate, just like a Trait is not the same as an Abstract Class. And the answers of that question do not satisfy me, see below.
#Blaisorblade, yes, it is a problem. For instances of each sub case class, the toBeOverride field are the same, so it should not appear in the constructor.
For now all the suggestions are to define an customized copy method in each(!) sub case class and that in my opinion is ugly and shows the incapability of the language.
The simplest solution is to just add the method you want to Base:
trait Base {
val toBeOverride: String
def copyBase(newToBeOverridden: String): Base
}
case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base {
def copyBase(newToBeOverridden: String) = copy(toBeOverride = newToBeOverridden)
}
This also allows to directly create an instance of Impl while specifying the value of toBeOverride (which wasn't possible). The only disadvantage is that now pattern matches using Impl have to change syntax - please update your question and add a comment if that's a problem.
BTW, if you just want to add a prefix (as in your example), that's no problem:
case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base {
def copyBase(newToBeOverridden: String) = copy(toBeOverride = toBeOverride + newToBeOverridden)
}
Here are two mechanisms.
Apparently, in the near future you'll be able to write a macro that can emit the anonymous subclass, but until then, I think this typeclass is not arduous.
Just kicking the tires on Dynamic here.
import scala.language.dynamics
import scala.reflect._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._
trait Base {
def m: String
}
case class Impl(p: Int) extends Base {
override val m = "some value"
}
trait Basic extends Dynamic {
protected def m: String
def selectDynamic(f: String): Any =
if ("m" == f) m else reflecting(this, f)
protected def reflecting(b: Basic, f: String) = {
val im = cm.reflect(b)
val member = im.symbol.typeSignature member newTermName(f)
require(member != NoSymbol, s"No such member $f")
(im reflectMethod member.asMethod)()
}
}
case class Implic(p: Int) extends Basic {
override protected val m = "some value"
}
object Test extends App {
implicit class Copy[A <: Base](val b: A) {
def overriding(overm: String): A = (b match {
case impl: Impl => new Impl(impl.p) { override val m = overm }
case b: Base => new Base { override val m = overm }
}).asInstanceOf[A]
}
implicit class Proxy[A <: Basic : ClassTag](val b: A) {
def proximately(overm: String): Basic = new Basic {
override val m = overm
override def selectDynamic(f: String): Any =
if ("m" == f) overm else reflecting(b, f)
override def toString = b.toString
}
}
// asked for this
//def overriding[T <: Base](v: Base) = v.copy(m = "prefix" + v.m)
/* want something like this
def overriding[T <: Base](v: Base) = new Impl(v.p) {
override val m = "some value"
} */
val a = Impl(5)
val b = a overriding "bee good"
Console println s"$a with ${a.m} ~> $b with ${b.m}"
// or
val c = Implic(7)
val d = c proximately "dynomite"
Console println s"$c with ${c.m} ~> $d with ${d.m}"
}
Since traits don't get copy methods automatically, you can try using a Base case class instead:
case class Base(toBeOverride: String)
case class Impl(other: Int, someVal: String = "some value") extends Base(someVal)
def overrideBaseValue[T <: Base](v: Base) =
v.copy(toBeOverride = "prefix" + v.toBeOverride)
The problem that you're going to run into though, is that copy returns an instance of Base and I don't think that you can convert it back to your original Impl class. For instance, this won't compile:
def overrideBaseValue[T <: Base](v: T): T =
v.copy(toBeOverride = "prefix" + v.toBeOverride)

Implicit parameter resolution - setting the precedence

I am trying to create a typeclass Default that supplies the default value for a given type. Here is what I have come up with so far:
trait Default[A] {
def value: A
}
object Default {
def withValue[A](a: A) = new Default[A] {
def value = a
}
def default[A : Default]: A = implicitly[Default[A]].value
implicit val forBoolean = withValue(false)
implicit def forNumeric[A : Numeric] =
withValue(implicitly[Numeric[A]].zero)
implicit val forChar = withValue(' ')
implicit val forString = withValue("")
implicit def forOption[A] = withValue(None : Option[A])
implicit def forAnyRef[A >: Null] = withValue(null : A)
}
case class Person(name: String, age: Int)
case class Point(x: Double, y: Double)
object Point {
implicit val pointDefault = Default withValue Point(0.0, 0.0)
}
object Main {
def main(args: Array[String]): Unit = {
import Default.default
println(default[Int])
println(default[BigDecimal])
println(default[Option[String]])
println(default[String])
println(default[Person])
println(default[Point])
}
}
The above implementation behaves as expected, except for the cases of BigInt and BigDecimal (and other user defined types that are instances of Numeric) where it gives null instead of zero. What should I do so that forNumeric takes precedence over forAnyRef and I get the behavior I expect?
The forAnyRef implicit is chosen because it is more specific than forNumeric according to §6.26.3 “Overloading Resolution” of the Scala reference. There is a way to reduce its priority by moving it to a trait that Default extends, like this:
trait LowerPriorityImplicits extends LowestPriorityImplicits {
this: Default.type =>
implicit def forAnyRef[A >: Null] = withValue(null: A)
}
object Default extends LowerPriorityImplicits {
// as before, without forAnyRef
}
But that's only part of the trick, because now both forAnyRef and forNumeric are as specific as each other, and you'll get an ambiguous-implicit error. Why is that? Well, forAnyRef gets an extra specificity point because it has a non-trivial constraint on A: A >: Null. What you can do then, to add a nontrivial constraint to forNumeric, is to double it in Default:
implicit def forNumericVal[A <: AnyVal: Numeric] = withValue(implicitly[Numeric[A]].zero)
implicit def forNumericRef[A <: AnyRef: Numeric] = withValue(implicitly[Numeric[A]].zero)
Now, this additional constraint makes forNumericVal and forNumericRef more specific that forAnyRef for types where a Numeric is available.
Here is another way to solve the problem, doesn't require any code duplication:
trait Default[A] {
def value: A
}
object Default extends LowPriorityImplicits {
def withValue[A](a: A) = new Default[A] {
def value = a
}
def default[A : Default]: A = implicitly[Default[A]].value
implicit val forBoolean = withValue(false)
implicit def forNumeric[A : Numeric] =
withValue(implicitly[Numeric[A]].zero)
implicit val forChar = withValue(' ')
implicit val forString = withValue("")
implicit def forOption[A] = withValue(None : Option[A])
}
trait LowPriorityImplicits { this: Default.type =>
implicit def forAnyRef[A](implicit ev: Null <:< A) = withValue(null : A)
}
case class Person(name: String, age: Int)
case class Point(x: Double, y: Double)
object Point {
implicit val pointDefault = Default withValue Point(0.0, 0.0)
}
object Main {
import Default.default
def main(args: Array[String]): Unit = {
println(default[Int])
println(default[BigDecimal])
println(default[Option[String]])
println(default[String])
println(default[Person])
println(default[Point])
}
}

Scala: Do implicit conversions work on Any?

I would like to store some objects from different type hierarchy into List[Any] or similar container, but perform implicit conversions on them later on to do something like type class.
Here is an example:
abstract class Price[A] {
def price(a: A): Int
}
trait Car
case class Prius(year: Int) extends Car
trait Food
case class FriedChicken() extends Food
object Def {
// implicit object AnyPrices extends Price[Any] {
// def price(any: Any) = 0
// }
// implicit object PriusPrices extends Price[Prius] {
// def price(car: Prius) = 100
// }
implicit object CarPrices extends Price[Car] {
def price(car: Car) = 100
}
implicit object FoodPrices extends Price[Food] {
def price(food: Food) = 5
}
}
def implicitPrice[A: Price](x: A) = implicitly[Price[A]].price(x)
import Def._
val stuff: List[Any] = List(Prius(2010), FriedChicken())
stuff map { implicitPrice(_) }
The above code throws an error as follows:
error: could not find implicit value for evidence parameter of type Price[Any]
stuff map { implicitPrice(_) }
^
If you uncomment AnyPrices, you'd get List(0,0), but that's not what I am expecting.
Do I have to store the manifest into the list for this to work?
Also, List(Prius(2010)) map { implicitPrice(_) } doesn't work either because it wants Price[Prius] and Price[Car] isn't good enough. Is there a way to make it more flexible?
So, looks like I can't get a type class once the objects are reduced to Any. My attempt of using Manifest also failed, since there seems to be no way for me to cast an Any into T even if I have the Manifest[T] object.
import reflect.Manifest._
def add [A, B >: A](stuff: A, list: List[(B, Manifest[_])])(implicit m: Manifest[A]) = (stuff, m) :: list
val stuff2 = add(Prius(2000), add(FriedChicken(), Nil))
stuff2 map { x =>
val casted = x._2.erasure.cast(x._1)
implicitPrice(casted)
}
gives me
error: could not find implicit value for evidence parameter of type Price[Any]
so it seems like I have to resolve things into Price before I stick them into List:
abstract class Price[A] {
def price(a: Any): Int
}
trait Car
case class Prius(year: Int) extends Car
trait Food
case class FriedChicken() extends Food
object Def {
implicit object PriusPrices extends Price[Prius] {
def price(car: Any) = 100
}
implicit object FriedChickenPrices extends Price[FriedChicken] {
def price(food: Any) = 5
}
}
import Def._
def add [A, B >: A](stuff: A, list: List[(B, Price[_])])(implicit p: Price[A]) = (stuff, p) :: list
val stuff = add(Prius(2000), add(FriedChicken(), Nil))
stuff map { x => x._2.price(x._1) }