scala type classes implicit ambiguity - scala

I have a problem setting up type classes in an algebraic type hierarchy.
I have the following traits:
trait Field[F]{...}
trait VectorSpace3[V,F] extends Field[F]{...}
Know I want to provide implementations:
trait DoubleIsField extends Field[Double]{
...
}
trait DoubleTurple3IsVectorSpace3 extends VectorSpace3[(Double,Double,Double), Double] with Field[Double]{
...
}
trait MyOtherClassIsVectorSpace3 extends VectorSpace3[MyOtherClass, Double] with Field[Double]{
...
}
//now the implicits
implicit object DoubleIsField extends DoubleIsField
implicit object DoubleTurple3IsVectorSpace3 extends DoubleTurple3IsVectorSpace3 with DoubleIsField
implicit object MyOtherClassIsVectorSpace3 extends MyOtherClassIsVectorSpace3 with DoubleIsField
The last two implicits lead to ambiguity: DoubleIsField is a part of 3 implicit values, code does not compile. How to deal with this issue in scala ?
EDIT:
Error:
ambiguous implicit values:
[error] both object DoubleIsField in object TypeClasses of type
Russoul.lib.common.TypeClasses.DoubleIsField.type
[error] and object DoubleTurple3IsVectorSpace3 in object TypeClasses of type
Russoul.lib.common.TypeClasses.DoubleTurple3IsVectorSpace3.type
[error] match expected type Russoul.lib.common.TypeClasses.Field[...Double]
EDIT2:
def func()(implicit env: Field[Double]): Unit ={
}
func()
Full testing program:
object Test extends App {
trait Field[F]{
}
trait VectorSpace3[V,F] extends Field[F]{
}
trait DoubleIsField extends Field[Double]{
}
trait DoubleTurple3IsVectorSpace3 extends VectorSpace3[(Double,Double,Double), Double] with Field[Double]{
}
//now the implicits
implicit object DoubleIsField extends DoubleIsField
implicit object DoubleTurple3IsVectorSpace3 extends DoubleTurple3IsVectorSpace3 with DoubleIsField
def func()(implicit env: Field[Double]): Unit ={
}
func()
}

(Updated in light of your recent comment...)
The problem is the definition of the following function:
def func()(implicit env: Field[Double]): Unit = {
// ...
}
Your issue is that you have multiple implicit values of this type in the same scope, and so the compiler cannot know which one to provide (they are all implicit values that can be expressed as having the type Field[Double]).
The whole point about implicit argument values is that there be a single value that can be identified by the compiler; if it can't identify one, it can't read your mind and pick the right one, nor would you want it to pick one at random.
The options you have available are as follows:
Forego using implicit argument values and pass values to your function explicitly.
Change the definition of the functions with implicit arguments to be types having unique implicit values.
Make do with a single implicit object definition. (Apologies for missing this off the list initially.)

Related

Extending an object with a trait which needs implicit member

I'm trying to have a code like below:
object MetaData extends CacheParams{}
So, since CacheParams needs implicit val p:Parameters, I tried:
object MetaData (implicit val p: Parameters) extends CacheParams
But it seems that I can't pass arguments to an object.
( because it gives error:traits or objects may not have parameters)
And if I don't pass any arguments it will give compile error that:
[error]: object creation impossible, since value p in trait CacheParams of type Parameters is not defined
I have no idea how to make this works. There were a few similar questions, but none of their answers solved my problem. Any help would be really appreciated.
Thanks a lot.
If I guessed the definition of CacheParams correctly
trait Parameters
trait CacheParams {
implicit val p: Parameters
}
then you should: (1) replace the object
object MetaData /*(implicit val p: Parameters)*/ extends CacheParams
//object creation impossible. Missing implementation for:
// implicit val p: Parameters // inherited from trait CacheParams
with a class
class MetaData(implicit val p: Parameters) extends CacheParams
or (2) implement the implicit inside the object
object MetaData extends CacheParams {
override implicit val p: Parameters = new Parameters {}
}
or
implicit val params: Parameters = new Parameters {} // suppose an implicit is in current scope
object MetaData extends CacheParams {
override implicit val p: Parameters = {
val p = ??? // hiding above p to avoid ambiguous implicits, null or NPE, see (*) below
implicitly[Parameters]
}
}
(*) NullPointerException on implicit resolution
In (1) you're defining/resolving implicit now in current scope. In (2) you postpone resolving implicit till instantiating the class (resolving implicit in the scope of class constructor call site).
See also Pass implicit parameter through multiply objects
Yeah that would solve my problem. But I wanted to keep the object's body clean and decoupled from the configuration in Parameters, like the classes' bodies that accept the p: Parameters.
If in (1) you want to decouple the object from "the configuration in Parameters" you can try to introduce a trait (ParamsMaterializer):
object MetaData extends CacheParams with ParamsMaterializer
trait ParamsMaterializer {
implicit val p: Parameters = new Parameters {}
}
or
implicit val params: Parameters = new Parameters {} // suppose an implicit is in current scope
object MetaData extends CacheParams with ParamsMaterializer
trait ParamsMaterializer {
implicit val p: Parameters = {
val p = ???
implicitly[Parameters]
}
}

Scala: Shapeless Generic with universal traits

I am trying to get hold of a shapeless Generic for a case class with a marker trait, like this:
case class X(a:String)
trait UniversalTrait extends Any {}
object MyApp extends App {
val ok = Generic[X]
val notOk = Generic[X with UniversalTrait]
}
It doesn't compile, with error could not find implicit value for parameter gen: shapeless.Generic[X with UniversalTrait] in the notOk line. Why is that? And can something be done?
Side note: I thought that it might be something to do with from not being able to add the marker trait to the returned instance, so I attempted fixing things by adding this:
object UniversalTrait {
implicit def genGeneric[P1<:Product with UniversalTrait,P2<:Product,L<:HList]
(implicit constraint: P1 =:= P2 with UniversalTrait,
underlying: Generic.Aux[P2,L]): Generic.Aux[P1,L] = new Generic[P1]{
type Repr=L
def to(t: P1): Repr = underlying.to(t)
def from(r: Repr): P1 = underlying.from(r).asInstanceOf[P1]
}
}
However, the error remains.
Deriving works for algebraic data types only.
That is a (sealed) trait and case classes (objects) extending the trait.
case class X(a:String) extends UniversalTrait
sealed trait UniversalTrait extends Any {}
val ok = Generic[X]

Default type class implementation in trait for sub-classes in Scala

I have the following relations:
trait Instrument
trait EquityOption extends Instrument { ... }
case class CallEquityOption(...) extends EquityOption
case class PutEquityOption(...) extends EquityOption
trait Priceable[I <: Instrument] { def price(I : Instrument) }
I can use exactly the same implementation of Priceable for the case classes CallEquityOptionand PutEquityOption. By having a match case to differentiation between the Call... and Put.... However, if I try to implement it directly as Priceable[EquityOption] under object EquityOption, the implicit cannot be found since it doesn't exactly match the type.
How can I make it work without needing to duplicate code?
You'll have to prove that you can provide an instance for every subtype of EquityOption.
implicit def allEquityOptions[T <: EquityOption]: Pricable[T] = ???

Generic inheritance in Scala

I'm trying to implement a few structures from Okasaki's book in Scala, and in tests try to keep the actual tests in the base class, only using subclasses to provide the instance-under-test.
For example, a test for unbalanced (tree) set looks as follows:
class UnbalancedSetSpec
extends SetSpec(new UnbalancedSet[Int])
with IntElements
where
abstract class SetSpec[E, S](val set: Set[E, S]) extends Specification with ScalaCheck {
implicit def elements: Arbitrary[E]
// ...
private def setFrom(es: Seq[E]): S = es.foldRight(set.empty)(set.insert)
}
Now sometimes I want to specialise the child spec, e.g.
class RedBlackSetSpec
extends SetSpec(new RedBlackSet[Int])
with IntElements {
"fromOrdList" should {
"be balanced" ! prop { (a: List[Int]) =>
val s = RedBlackSet.fromOrdList(a.sorted)
set.isValid(s) should beTrue
}
}
}
it fails because there's no method isValid on Set[E, S] — it's defined in RedBlackSet[E]. But if I go ahead and change SetSpec[E, S](val set: Set[E, S]) to SetSpec[E, S, SES <: Set[E, S]](val set: SES), this particular problem disappears, but the code still fails to compile:
Error:(7, 11) inferred type arguments [Nothing,Nothing,okasaki.RedBlackSet[Int]] do not conform to class SetSpec's type parameter bounds [E,S,SES <: okasaki.Set[E,S]]
extends SetSpec(new RedBlackSet[Int])
^
Error:(7, 11) inferred type arguments [Nothing,Nothing,okasaki.UnbalancedSet[Int]] do not conform to class SetSpec's type parameter bounds [E,S,SES <: okasaki.Set[E,S]]
extends SetSpec(new UnbalancedSet[Int])
^
The definition of RedBlackSet is as follows:
package okasaki
class RedBlackSet[E](implicit ord: Ordering[E]) extends Set[E, RBTree[E]] {
so I would expect E to be inferred as Int rather than Nothing, and S as RBTree[Int] — but it doesn't happen.
class RedBlackSetSpec
extends SetSpec[Int, RedBlackSet.RBTree[Int], RedBlackSet[Int]](new RedBlackSet[Int])
with IntElements {
and
class UnbalancedSetSpec
extends SetSpec[Int, BinaryTree[Int], UnbalancedSet[Int]](new UnbalancedSet[Int])
with IntElements
work fine, but look ugly.
I'm struggling to understand why E and S are not inferred here. Any hints?
This is actually a well-known problem with Scala type inference: it can't infer SES "first" and use it to infer E and S. One solution comes to mind:
class RedBlackSetSpec(override val set: RedBlackSet[Int]) extends SetSpec(set) with IntElements {
def this() = this(new RedBlackSet[Int])
...
}
It becomes less ugly if you make set in SetSpec an abstract val instead of a constructor argument, but with a slight tradeoff in cases you don't need to specialize. I think there should be a better one, but this should work.

How to trick Scala to not find duplicate implicits for Nothing

I am trying to use the typeclass pattern in Scala to mark all the valid API serializable types, so that we can have compile-time safety around what we serialize. Our underlying library accepts an AnyRef which can lead to weird errors when not explicitly declaring the type before serializing it.
We allow sending out a public model, an iterable of public models, an option of public model, or a unit.
trait PublicModel
case class UserModel(name: String) extends PublicModel
sealed class SafeForPublic[-T]
implicit object PublicModelOk extends SafeForPublic[PublicModel]
implicit object IterablePublicModelOk extends SafeForPublic[Iterable[PublicModel]]
implicit object OptionPublicModelOk extends SafeForPublic[Option[PublicModel]]
implicit object UnitOk extends SafeForPublic[Unit]
This method works well for everything except methods where the parameter type is an option. This is because None is an Option[Nothing], so T = Nothing which will tell the compiler to look up an implicit object of type SafeForPublic[Nothing] and it will find both SafeForPublic[PublicModel] as well as SafeForPublic[Iterable[PublicModel]]
def boxed[T : SafeForPublic](t: Option[T]) = println("wooohoo!")
boxed(Some(None)) // works
boxed(Some(1)) // doesn't compile. Int is not a valid serializable model.
boxed(Some({})) // works
boxed(Some(UserModel("ok"))) // works
boxed(Some(Seq(UserModel("ok")))) // works
boxed(None) // doesn't compile, duplicate implicits ><
Any idea how I can trick the compiler to not find duplicate implicits for Nothing. I saw Miles Sabin had a trick using:
sealed trait NotNothing[A]{
type B
}
object NotNothing {
implicit val nothing = new NotNothing[Nothing]{ type B = Any }
implicit def notNothing[A] = new NotNothing[A]{ type B = A }
}
But I couldn't figure out how to use it. Halp?
Ok, thanks to some help from the Scala IRC channel, I figured out that LowPriority implicits was created to solve this issue.
I used this to fix it:
sealed class SafeForPublic[-T]
trait LowPriorityImplicits {
implicit object PublicModelOk extends SafeForPublic[PublicModel]
implicit object IterablePublicModelOk extends SafeForPublic[Iterable[PublicModel]]
implicit object OptionPublicModelOk extends SafeForPublic[Option[PublicModel]]
implicit object UnitOk extends SafeForPublic[Unit]
}
object Implicits extends LowPriorityImplicits {
implicit object NothingOk extends SafeForPublic[Nothing]
}
import Implicits._
def boxed[T : SafeForPublic](t: Option[T]) = println("woohoo!")
boxed(None) // compiles! \o/