My goal is to equip a variety of types (Timestamps, Dates, etc.) with nice properties they might not have by default (ordering, -, etc.). I'm doing something like this:
trait NiceProperties[T] {
def -(t: T): Double
def +(d: Double): T
...
}
implicit class BetterTimestamp(val t: Timestamp) extends NiceProperties[Timestamp] {
override def -(Timestamp): ...
}
This all works fine until I need to pass it into a function that assumes NiceProperties:
def myUtil[T](t: NiceProperties[T]): T = {
(t + 1.0) + 1.0
}
This now fails, because the function lacks the implicit evidence that the class T can be implicitly upcast to NiceProperties[T], so it can't add (t + 1.0): T to a double.
Is there a way to pass evidence for an implicit class into a function? Alternatively, is there a better pattern for this?
You could solve your issue by turning your NiceProperties[T] into a class that knows how to add, sum, ... two values of type T:
trait NiceProperties[T] {
def subtract(a: T, b: T): Double
def add(a: T, d: Double): T
}
You can now create an implicit NiceProperties object or val for Timestamps, Dates, ...
object BetterTimestamp extends NiceProperties[Timestamp] {
def subtract(a: Timestamp, b: Timestamp): Double = ???
def add(a: Timestamp, d: Double): Timestamp = ???
}
In your example method you'll request an implicit NiceProperties[T] which does the operations for your.
def myUtil[T](t: T)(implicit prop: NiceProperties[T]): T = {
prop.add(prop.add(t, 1.0), 1.0)
}
Since this is ugly, you can use an implicit class to add the +, -, ... operators to any class where an implicit NiceProperties[T] is available:
implicit class NicePropertiesOps[T](t: T)(implicit prop: NiceProperties[T]) {
def +(d: Double): T = prop.add(t, d)
def -(b: T): Double = prop.subtract(t, b)
}
Now your example from above should work almost as you described.
def myUtil[T : NiceProperties](t: T): T = {
(t + 1.0) + 1.0
}
https://scastie.scala-lang.org/0D1Y9sE5S5mrzm9coZPMWw
#Aki's answer is completely correct. Here is just an alternative approach of bringing the conversion into scope. This way is used in Numeric typeclass.
class Timestamp
trait NiceProperties[T] {
def subtract(a: T, b: T): Double
def add(a: T, d: Double): T
implicit class Ops(t:T) {
def +(d: Double): T = add(t, d)
def -(b: T): Double = subtract(t, b)
}
}
implicit object BetterTimestamp extends NiceProperties[Timestamp] {
def subtract(a: Timestamp, b: Timestamp): Double = ???
def add(a: Timestamp, d: Double): Timestamp = ???
}
def myUtil[T](t: T)(implicit prop: NiceProperties[T]): T = {
import prop._
(t + 1.0) + 1.0
}
and one more approach just of fun. This is how to avoid import:
trait NiceProperties[T] extends (T => Ops[T]) {
def subtract(a: T, b: T): Double
def add(a: T, d: Double): T
implicit val v = this
def apply(t:T) = new Ops(t)
}
class Ops[T](t:T)(implicit prop: NiceProperties[T]) {
def +(d: Double): T = prop.add(t, d)
def -(b: T): Double = prop.subtract(t, b)
}
implicit object BetterTimestamp extends NiceProperties[Timestamp] {
def subtract(a: Timestamp, b: Timestamp): Double = ???
def add(a: Timestamp, d: Double): Timestamp = ???
}
def myUtil[T:NiceProperties](t: T): T = {
(t + 1.0) + 1.0
}
The existing answers are good, but, in cases where you can't modify the trait, you can require the implicit conversion as a parameter:
def myUtil[T](t: T)(implicit conv: T => NiceProperties[T]) = t + 1.0 + 1.0
If you're doing this a lot, you might add an abstract type so you can use a context bound:
type HasNiceProperties[T] = T => NiceProperties[T]
def myUtil[T : HasNiceProperties](t: T) = t + 1.0 + 1.0
Related
I want to overloading constructor of abstract class with specific type. For example, I have:
abstract class Polinom(v: T)
So, when I create Polinom[String], I want to call constructor(String), for Int I want to call constructor(Int). If T != String and T != Int then I call constructor(T). In addition, for T == Int my object must have method add, for T == String - reverse, for T != String and T != Int object doesn't has this methods. How can I do that?
You can use evidence parameters for this:
class Polinom[T](v: T) {
def add(i: Int)(implicit ev: T <:< Int) = v + i
def reverse(implicit ev: T <:< String): String = ev(v).reverse
}
val x = new Polinom(50)
val y = new Polinom("hello")
val z = new Polinom(None)
println(x.add(3))
println(y.reverse)
//println(z.add(3)) <- Isn't allowed. Error: Cannot prove that None.type <:< Int
If you want specific constructors for Int and String and can't get enough of that implicit evidence, you can do this:
def this(i: Int)(implicit ev: Int =:= T) = this({
//do special int stuff here
println("I am in the special int constructor")
ev(i)
})
def this(s: String)(implicit ev: String =:= T) = this({
//do special string stuff here
println("I am in the special string constructor")
ev(s)
})
EDIT: Apparently, the above didn't work for the OP, although it seems to be working for me, but you can always make a companion object and overload the apply method, as the other answers suggested.
class Polinom[T] private(v: T)
object Polinom {
def apply(i: Int): Polinom[Int] = new Polinom(i)
def apply(s: String): Polinom[String] = new Polinom(s)
def apply[T](x: T): Polinom[T] = new Polinom(x)
}
val x = Polinom(50)
val y = Polinom("hello")
val z = Polinom(None)
println(x.add(3))
println(y.reverse)
//println(z.add(3)) <- Isn't allowed. Error: Cannot prove that None.type <:< Int
Link to Scastie (the demo's below)
<script src="https://scastie.scala-lang.org/j8fWjvVFS3CumCo3WbUgqQ.js"></script>
It would be better to model that as an ADT, something like:
sealed trait Polinom[T] {
def v: T
}
object Polinom {
final case class IntPolinom private[Polinom] (v: Int) extends Polinom[Int] {
def add(x: Int): IntPolinom =
this.copy(v = this.v + x)
}
final case class StrPolinom private[Polinom] (v: String) extends Polinom[String] {
def reverse: StrPolinom =
this.copy(v = this.v.reverse)
}
final case class GenericPolinom[T] private[Polinom] (v: T) extends Polinom[T]
def apply[T](v: Int): IntPolinom =
IntPolinom(v)
def apply[T](v: String): StrPolinom =
StrPolinom(v)
def apply[T](v: T): GenericPolinom[T] =
GenericPolinom(v)
}
abstract class Polinom[T](v: T)
object Polinom {
def apply(i: Int): Polinom[Int] = constructor(i)
def apply(s: String): Polinom[String] = constructor(s)
def apply[T](v: T): Polinom[T] = constructor(v)
}
Polinom(0)
Polinom("hello")
Polinom(None)
For examples of the add and reverse methods, see the other answers to this question.
I have been trying to create some sort of a typeclass and encountered problems with implicit resolution.
Basically I want to generate random data and adjust parameters of generation - interval for numbers, length and interval for arrays, etc.
Here is what I've got by now:
import scala.util.Random
trait PrimitiveGenerator[T <: AnyVal, Bounds] {
def generate(bounds: Bounds): T
def generatePossibly(bounds: Bounds): Option[T] = if (Random.nextDouble() < 0.5) None else Some(generate(bounds))
}
object PrimitiveGenerator {
def apply[A <: AnyVal](implicit impl: PrimitiveGenerator[A, _]) = impl
}
object Generators {
implicit object IntGenerator extends PrimitiveGenerator[Int, (Int, Int)] {
override def generate(bounds: (Int, Int) = (0, 1)): Int = Random.nextInt((bounds._2 - bounds._1) + 1) + bounds._1
}
}
object Test extends App {
import Generators._
PrimitiveGenerator[Int].generate((0, 1)) //error is here
}
In Intellij Idea this is failing with:
found : (Int, Int)
required: _$1 where type _$1
PrimitiveGenerator[Int].generate((0, 1))
I have an inkling that using underscore is wrong here, but how could I rewrite it to summon an instance of DataGenerator based only on first type parameter(A). It seems perfectly safe from compilation perspective:
if compiler finds DataGenerator for Int, only in one example, it will use it right away, if it finds several of them with different Bounds, just returns an error. This error I could possibly solve adding this parameter to implicit resolution. So what do you think?
Edit 1
Thanks to #Dmytro Mitin for solving it!
Looking further, I wanted to make an implementation for Array, so that if we want to summon an instance for an array we should have an instance for Array's parameter type, like this:
import scala.reflect.ClassTag
import scala.util.Random
trait PrimitiveGenerator[T] {
type Bounds
def generate(bounds: Bounds): T
def generatePossibly(bounds: Bounds): Option[T] = if (Random.nextDouble() < 0.5) None else Some(generate(bounds))
}
object PrimitiveGenerator {
type Aux[T, Bounds0] = PrimitiveGenerator[T] { type Bounds = Bounds0 }
def apply[A](implicit impl: PrimitiveGenerator[A]): Aux[A, impl.Bounds] = impl
}
object Generators {
implicit object IntGenerator extends PrimitiveGenerator[Int] {
override type Bounds = (Int, Int)
override def generate(bounds: (Int, Int) = (0, 1)): Int = Random.nextInt((bounds._2 - bounds._1) + 1) + bounds._1
}
implicit def toGenericArrayGenerator[A](implicit generator: PrimitiveGenerator[A],
classTag: ClassTag[A]): PrimitiveGenerator[Array[A]] = new PrimitiveGenerator[Array[A]] {
override type Bounds = ((Int, Int), generator.Bounds) //It means generate array of length from n to m where elements comply to Bounds of base generator
override def generate(bounds: Bounds): Array[A] = {
Array[A]()
}
}
}
object Test extends App {
import Generators._
println(PrimitiveGenerator[Int].generate((0, 42)))
PrimitiveGenerator[Array[Int]].generate((1 -> 10, 0 -> 42))
}
Now I am trying to create array generator dynamically and the Bounds are slightly changed depending on base generator bounds(by plan).
But something went wrong and now I have:
Error: type mismatch;
found : ((Int, Int), (Int, Int))
required: impl.Bounds
PrimitiveGenerator[Array[Int]].generate((1 -> 10, 0 -> 42))
How can it be resolved?
For example try
object PrimitiveGenerator {
def apply[A <: AnyVal] = new PartiallyApplied[A]
class PartiallyApplied[A <: AnyVal] {
def apply[B]()(implicit impl: PrimitiveGenerator[A, B]) = impl
}
}
object Test extends App {
import Generators._
PrimitiveGenerator[Int]().generate((0, 1))
}
or
object PrimitiveGenerator {
def generate[A <: AnyVal, B](b: B)(implicit impl: PrimitiveGenerator[A, B]) = impl.generate(b)
}
object Test extends App {
import Generators._
PrimitiveGenerator.generate((0, 1))
}
or
trait PrimitiveGenerator[T <: AnyVal] {
type Bounds
def generate(bounds: Bounds): T
def generatePossibly(bounds: Bounds): Option[T] = if (Random.nextDouble() < 0.5) None else Some(generate(bounds))
}
object PrimitiveGenerator {
type Aux[T <: AnyVal, Bounds0] = PrimitiveGenerator[T] { type Bounds = Bounds0 }
def apply[A <: AnyVal](implicit impl: PrimitiveGenerator[A]): Aux[A, impl.Bounds] = impl
}
object Generators {
implicit object IntGenerator extends PrimitiveGenerator[Int] {
override type Bounds = (Int, Int)
override def generate(bounds: (Int, Int) = (0, 1)): Int = Random.nextInt((bounds._2 - bounds._1) + 1) + bounds._1
}
}
object Test extends App {
import Generators._
PrimitiveGenerator[Int].generate((0, 1))
}
or
trait PrimitiveGenerator[T <: AnyVal] {
type Bounds = (T, T)
def generate(bounds: Bounds): T
def generatePossibly(bounds: Bounds): Option[T] = if (Random.nextDouble() < 0.5) None else Some(generate(bounds))
}
object PrimitiveGenerator {
def apply[A <: AnyVal](implicit impl: PrimitiveGenerator[A]): PrimitiveGenerator[A] = impl
}
object Generators {
implicit object IntGenerator extends PrimitiveGenerator[Int] {
override def generate(bounds: (Int, Int) = (0, 1)): Int = Random.nextInt((bounds._2 - bounds._1) + 1) + bounds._1
}
}
object Test extends App {
import Generators._
PrimitiveGenerator[Int].generate((0, 1))
}
I've recently started learning Scala's implicit "magic" and I'm having troubles with implicit Scala objects. I've tried all the possible variants but nothing seems to work.
Lets assume I have a class like this with some solve() function. It should return 2 Float values if the input a, b were Float. Otherwise it should return another type values:
class Solver[T](val a: T, val b: T) {
def solve[A](implicit num: customNumeric[T]): Option[(T, T)] = {
Option(
num.f(num.g(a)),
num.f(num.g(b)))
}
}
Let's assume another-type-value is an object of class like this:
class MyClass[T] (x: T, y: T)(implicit num: customNumeric[T]) {
val field : T = num.f(x)
}
And let's also assume that I dont have the functions I need in basic Scala Numeric so I should make my own custom numeric.
Here is what I've done:
I've made an abstract class for my own customNumeric with my methods f() and g() and couple of implicit objects that extend my customNumeric for some value types (Int, Float for example) and implemented method in them:
abstract class customNumeric[T] {
def f(x: T): T
def g(x: T): T
}
object customNumeric {
implicit object IntIsCustomNumeric extends customNumeric[MyClass[Int]] {
def f(x: MyClass[Int]) = new MyClass[Int](x.field + 5)
def g(x: MyClass[Int]) = new MyClass[Int](x.field - 5)
}
implicit object FloatIsCustomNumeric extends customNumeric[Float] {
def f(x: Float): Float = x + 3
def g(x: Float): Float = x - 3
}
}
In my opinion Solver's solve() should use implicit customNumeric object to get implementations for methods referenced inside solve() based upon type of the Solver's input values.
But this doesn't work as compiler says:
could not find implicit value for parameter num: customNumeric[Int]
def f...
It also complains because of not enough arguments for constructor MyClass at the same line.
I've already tried making companion object to cast Int to MyClass:
object Fraction {
implicit def int2MyClass(x: Int): MyClass[Int] = new MyClass[Int](x, 1)
}
But that also doen't seem to work. And I've tried to make another implicit object to implement methods I use in customNumeric[MyClass[Int]].
Do you have any ideas? Thanks in advance!
The problem is that you're trying to define the implicit objects with classes that themselves require that same implicit object.
Meaning, this:
class MyClass[T] (x: T, y: T)(implicit num: CustomNumeric[T])
Requires an existence of an implicit CustomNumeric[T]. You cannot define IntIsCustomNumeric using that type:
implicit object IntIsCustomNumeric extends customNumeric[MyClass[Int]]
When you implement IntIsCustomNumeric, you need to implement it for type Int, not for type MyClass[Int]. When you do that, i.e:
object CustomNumeric {
implicit object IntIsCustomNumeric extends CustomNumeric[Int] {
override def f(x: Int): Int = x
override def g(x: Int): Int = x
}
}
Now, you can create an Solver[Int] which takes an implicit CustomNumeric[Int]:
def main(args: Array[String]): Unit = {
import CustomNumeric._
val solver = new Solver[Int](1, 2)
println(solver.solve)
}
Now, it's also easier to create an implicit conversion from an Int type to something that creates a MyClass[Int]:
implicit object MyClassIsCustomNumeric extends CustomNumeric[MyClass[Int]] {
override def f(x: MyClass[Int]): MyClass[Int] = new MyClass[Int](x.field + 5)
override def g(x: MyClass[Int]): MyClass[Int] = new MyClass[Int](x.field + 3)
}
implicit def intToMyClass(i: Int) = new MyClass[Int](i)
What do you think about this
object customNumeric {
implicit object IntIsCustomNumeric extends customNumeric[Int] {
def f(x: Int): Int = x + 3
def g(x: Int): Int = x - 3
}
implicit object FloatIsCustomNumeric extends customNumeric[Float] {
def f(x: Float): Float = x + 3
def g(x: Float): Float = x - 3
}
implicit def int2MyClass(x: Int): MyClass[Int] = new MyClass[Int](x, 1)
implicit object cn extends customNumeric[MyClass[Int]] {
def f(x: MyClass[Int]) = x.field + 5
def g(x: MyClass[Int]) = x.field - 5
}
}
I'v been playing around with scala again testing some language type check features. I'm trying to implement a vector library intened for use with graphics and I want to use the scala typechecker as much as possible to get early compile time warnings when using it. What I'v got so far.
trait VecT
abstract sealed class Vec[T,V[T] <: VecT](elems: T*)(implicit num: VecIntegral[T]) extends VecT {
import num._
def +(v: V[T]): V[T] = ???
def -(v: V[T]): V[T] = ???
def cross(v: V[T]): V[T] = ???
def dot(v: V[T]): T = ???
def unary_-(): V[T] = ???
def *(scalar: T): V[T] = ???
def abs: T = ???
def *(v: V[T]): V[T] = cross(v)
def apply(n: Int): T = ???
}
class Vec2[T](x: T, y: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec2](x,y)
class Vec3[T](x: T, y: T, z: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec3](x,y,z)
this allows me to do compile time checking for operations like even if the + operator is implemented in the abstract class
(new Vec3[Int](1,2,3)) + (new Vec3[Int](1,2,3))
(new Vec3[Int](1,2,3)) + (new Vec2[Int](1,2)) // Failes compilation
which is what i want.
So far so good. Now i would like to have a map function implemented in the abstract class something like
def map[A](f: T => A): V[A] = Vec(elems.map(f):_*)
So my attempt of realizing this would be to create a general Vec factory
object Vec {
def apply[T, V[T] <: VecT](elemes: T*)(implicit num: VecIntegral[T]): V[T] = elems match {
case Seq(x,y) => new V[T](x,y)
case Seq(x,y,z) => new V[T](x,y,z)
}
but that wont work, expression of type V does not comform to exptected type V[T]
So my question. Is there any "good" general way of implementing a factory like this?
For why new V[T](...) doesn't and shouldn't work, see https://stackoverflow.com/a/39286308/9204. One solution would be
trait VecFactory[V[_]] { def newVec[T](elems: Seq[T]): V[T] }
abstract sealed class Vec[T,V[T] <: VecT](elems: T*)(implicit num: VecIntegral[T], factory: VecFactory[V]) {
def map[A](f: T => A): V[A] = factory.newVec(elems.map(f))
}
class Vec2[T](x: T, y: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec2](x,y)
object Vec2 {
implicit val factory: VecFactory[Vec2] = new VecFactory[Vec2] {
def newVec[T](elems: Seq[T]) = new Vec2(elems(0), elems(1))
}
}
class Vec3[T](x: T, y: T, z: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec3](x,y,z)
object Vec3 {
implicit val factory: VecFactory[Vec3] = ...
}
Note that this still isn't perfectly safe: the factories need to be called with sequences of specific length.
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])
}
}