I know view bounds may be deprecated soon. Please ignore that.
The following code compiles if only one of the last 3 implicit conversions are uncommented. Is this a compiler bug?
object Viewable extends App {
/** Speed of light in m/s */
val C: Double = 299293458d
/** #param weight in kilograms */
case class Matter(name: String, weight: Double) {
/** #return matter-energy equivalence in megajoules */
def energy: Double = weight * C * C / 1000000d
def megaJouleMsg: String = f"$name's mass-energy equivalence is $energy%.0f megajoules."
}
case class Animal(name: String, height: Double, weight: Double)
case class Vegetable(name: String, height: Double, weight: Double)
case class Mineral(name: String, weight: Double)
case class Bug(name: String, height: Double, weight: Double, canFly: Boolean)
case class Whale(name: String, height: Double, weight: Double, hasTeeth: Boolean)
case class AppleTree(name: String, height: Double, weight: Double, age: Int)
case class Grass(name: String, height: Double, weight: Double, edible: Boolean)
case class Sand(name: String, color: String, weight: Double)
case class Rock(name: String, color: String, weight: Double)
implicit def sandToMineral(sand: Sand) = Mineral(sand.name, sand.weight)
implicit def rockToMineral(rock: Rock) = Mineral(rock.name, rock.weight)
implicit def appleTreeToVegetable(tree: AppleTree) = Vegetable(tree.name, tree.height, tree.weight)
implicit def grassToVegetable(grass: Grass) = Vegetable(grass.name, grass.height, grass.weight)
implicit def bugToAnimal(bug: Bug) = Animal(bug.name, bug.height, bug.weight)
implicit def whaleToAnimal(whale: Whale) = Animal(whale.name, whale.height, whale.weight)
implicit def animalToMatter[X <% Animal](animal: X) = Matter(animal.name, animal.weight)
implicit def vegetableToMatter[X <% Vegetable](vegetable: X) = Matter(vegetable.name, vegetable.weight)
implicit def mineralToMatter[X <% Mineral](mineral: X) = Matter(mineral.name, mineral.weight)
println(Animal("Poodle", 1.0, 8.0).megaJouleMsg)
println(AppleTree("Spartan", 2.3, 26.2, 12).megaJouleMsg)
println(Rock("Quartz crystal", "white", 2.3).megaJouleMsg)
}
The error messages are:
type mismatch;
found : solutions.Viewable.Animal
required: ?{def megaJouleMsg: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method animalToMatter in object Viewable of type [X](animal: X)(implicit evidence$1: X => solutions.Viewable.Animal)solutions.Viewable.Matter
and method vegetableToMatter in object Viewable of type [X](vegetable: X)(implicit evidence$2: X => solutions.Viewable.Vegetable)solutions.Viewable.Matter
are possible conversion functions from solutions.Viewable.Animal to ?{def megaJouleMsg: ?}
println(Animal("Poodle", 1.0, 8.0).megaJouleMsg)
^
type mismatch;
found : solutions.Viewable.AppleTree
required: ?{def megaJouleMsg: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method animalToMatter in object Viewable of type [X](animal: X)(implicit evidence$1: X => solutions.Viewable.Animal)solutions.Viewable.Matter
and method vegetableToMatter in object Viewable of type [X](vegetable: X)(implicit evidence$2: X => solutions.Viewable.Vegetable)solutions.Viewable.Matter
are possible conversion functions from solutions.Viewable.AppleTree to ?{def megaJouleMsg: ?}
println(AppleTree("Spartan", 2.3, 26.2, 12).megaJouleMsg)
^
Well the compiler gives the error precisely. This is because there is more than one function which can Animal => Matter. i.e. your below 3 functions:
implicit def animalToMatter[X](animal: X) (implicit ev: X => Animal) = Matter(animal.name, animal.weight)
implicit def vegetableToMatter[X ](vegetable: X) (implicit ev: X => Vegetable) = Matter(vegetable.name, vegetable.weight)
implicit def mineralToMatter[X ](mineral: X) (implicit ev: X => Mineral) = Matter(mineral.name, mineral.weight)
are equally eligible to be called when you do Animal("Poodle", 1.0, 8.0).megaJouleMsg.
When you call megaJouleMsg the compiler looks for any implicit function available that can take Animal and return an object containing method megaJouleMsg (Matter in your case). Now all the 3 functions can take Animal (there is no constraint coded any where) and can return Matter. So the compiler gets confused on which function to calls
Solution: From what it appears, the view bound is not required. This will do:
implicit def animalToMatter(animal: Animal) = Matter(animal.name, animal.weight)
implicit def vegetableToMatter(vegetable: Vegetable) = Matter(vegetable.name, vegetable.weight)
implicit def mineralToMatter(mineral: Mineral) = Matter(mineral.name, mineral.weight)
scala> Animal("Poodle", 1.0, 8.0).megaJouleMsg
res1: String = Poodle's mass-energy equivalence is 716612592013 megajoules.
Edit: Looks like the confusion is because of X <% Animal. In animalToMatter function, it expects an implicit argument which can take X and return Animal. Now if you see in your scope there is no such function X => Animal. But because you are passing Animal("Poodle", 1.0, 8.0) it doesn't need any implicit function because it has already obtained Animal.
In short to repeat the compiler process on seeing Animal("Poodle", 1.0, 8.0).megaJouleMsg:
Sees all functions in the current scope which can take Animal and return Matter.
All the 3 functions can take Animal and return Matter. Note that vegetableToMatter and mineralToMatter will fail if accepted. i.e. though they are eligible but they will not succeed because they dont have any implicit function available that can X => Animal
Throws Error
As an example consider this:
scala> implicit def f[T <% Int](n:T) = Matter("",1)
warning: there were 1 feature warning(s); re-run with -feature for details
f: [T](n: T)(implicit evidence$1: T => Int)Matter
scala> 1.megaJouleMsg
res2: String = 's mass-energy equivalence is 89576574002 megajoules.
scala> "a".megaJouleMsg
<console>:12: error: No implicit view available from String => Int.
"a".megaJouleMsg
^
<console>:12: error: value megaJouleMsg is not a member of String
"a".megaJouleMsg
Notice the error? It gives:
No implicit view available from String => Int.
and not just value megaJouleMsg is not a member of String
Which simply means "a" was eligible for the implicit function f but f could not find a function that could convert it to Int and hence it gives error No implicit view available.... If it was not eligible for function f, then it would just throw error megaJouleMsg is not a member...
Related
Suppose I'd like to traverse case class generic representation as described here
I've defined some typeclass to describe fields:
trait Described[X] extends (X => String)
object Described{
def apply[X](x: X)(implicit desc: Described[X]) = desc(x)
}
Defined some instance:
implicit object DoubleDescribed extends Described[Double]{
def apply(x: Double) = x.formatted("%01.3f")
}
And general user:
import shapeless._
import shapeless.labelled.FieldType
import shapeless.ops.hlist.LeftFolder
object DescrFolder extends Poly2{
implicit def field[X, S <: Symbol](implicit desc: Described[X],
witness: Witness.Aux[S]):
Case.Aux[Seq[String], FieldType[S, X], Seq[String]] =
at[Seq[String], FieldType[S, X]](
(descrs, value) => descrs :+ f"${witness.value.name}: ${desc(value)}")
}
def describe[T <: Product, Repr <: HList](struct: T)
(implicit lgen: LabelledGeneric.Aux[T,Repr],
folder: LeftFolder.Aux[Repr, Seq[String], DescrFolder.type, Seq[String]]
): String = {
val repr = lgen.to(struct)
val descrs = folder(repr,Vector())
descrs.mkString(struct.productPrefix + "{", ",", "}")
}
So now i could write
case class Point(x: Double, y: Double, z: Double)
describe(Point(1,2,3.0))
and get
res1: String = Point{x: 1,000,y: 2,000,z: 3,000}
Now i'd like to define some field metadata using shapeless tags:
import tag._
trait Invisible
val invisible = tag[Invisible]
implicit def invisibleDescribed[X](implicit desc: Described[X])
: Described[X ## Invisible] =
new Described[X ## Invisible]{
def apply(x: X ## Invisible) = desc(x: X) + "[invisible]"
}
so Described(invisible(0.5)) now succesfully produces
res2: String = 0,500[invisible]
But with redefined
case class Point(x: Double, y: Double, z: Double ## Invisible)
describe(Point(1,2,invisible(3.0)))
yields compilation error:
Error: diverging implicit expansion for type
LeftFolder.Aux[this.Out,Seq[String],DescrFolder.type,Seq[String]]
starting with method invisibleDescribed in class ...
I presume that type X with Tag[Y] with KeyTag[K,X] is not identifying as FieldType[S, X] but could not guess how to fix it.
How could one define proper LeftFolder for such situation?
Your issue does not involve shapeless at all. It can be actually simplified as:
trait Described[T]
trait Invisible
implicit val doubleDescribed: Described[Double] = ???
implicit def invisibleDescribed[T](
implicit desc: Described[T]
): Described[T with Invisible] = ???
implicitly[Described[Double with Invisible]]
Double ## Invisible can be "represented" as Double with Invisible. Note that Double with Invisible <: Double.
When the compiler tries to get an implicit Described[Double with Invisible] it correctly complains about diverging implicit expansion: doubleDescribed and invisibleDescribed.
Going back to your original code, an easy fix could be to just rewrite invisibleDescribed as:
implicit def invisibleDescribed[X, I <: X ## Invisible](
implicit desc: Described[X]
): Described[I] = new Described[I]{
def apply(x: I) = desc(x: X) + "[invisible]"
}
I'm trying to define, what I think to be a "default argument", with an implicit argument:
scala> def f(implicit x: Int, y: String) = y
f: (implicit x: Int, implicit y: String)String
Note - I tried to define implicit x: Int as the second argument, but I got a compile-time error:
scala> def f(y: String, implicit x: Int) = y
<console>:1: error: identifier expected but 'implicit' found.
def f(y: String, implicit x: Int) = y
Anyway, I define an implicit Int.
scala> implicit val x: Int = 100
x: Int = 100
Then I failed to invoke f with just a String argument:
scala> f("foo")
<console>:10: error: not enough arguments for method f:
(implicit x: Int, implicit y: String)String.
Unspecified value parameter y.
f("foo")
^
Next, I tried to invoke the f function by specifying the argument. That failed too.
scala> f(y = "foo")
<console>:10: error: not enough arguments for method f:
(implicit x: Int, implicit y: String)String.
Unspecified value parameter x.
f(y = "foo")
^
Is it possible to invoke the function f by providing an implicit and providing only a single argument for y?
Implicit parameter sections are all or nothing—either you explicitly pass every argument (assuming they don't have default values) or none of them. You need to do something like this if you want f("foo") to work:
def f(y: String)(implicit x: Int) = y
I'd be careful about this approach, though—I'm personally increasingly inclined to think that using implicits for anything except type class instances is a bad idea, and having an implicit Int value floating around is kind of scary.
I've been working on some scala code that was compiling fine, but somehow I've broken the implicit conversions and I can't work out what I've done wrong. Boiling it down to a very simple case, this code doesn't compile and the reason seems to be that I'm not importing the implicit conversions between Double and Numeric[Double]:
import scala.math.Numeric
import scala.math.Numeric._
import scala.math.Numeric.Implicits._
import Ordering.Implicits._
object ImplicitNumericConversions {
val v: Numeric[Double] = 3.0
}
I can fix this easily enough by providing my own function:
import scala.math.Numeric
object ImplicitNumericConversions {
def convertDoubleToNumeric(d: Double)(implicit num: Numeric[Double]): Numeric[Double] = num
val v: Numeric[Double] = convertDoubleToNumeric(3.0)
}
If I make the conversion function implicit then I get what I'm looking for:
import scala.math.Numeric
object ImplicitNumericConversions {
implicit def convertDoubleToNumeric(d: Double)(implicit num: Numeric[Double]): Numeric[Double] = num
val v: Numeric[Double] = 3.0
}
... but why don't the imports from scala.math.Numeric do this for me?
The actual problem that I'm working on looks like this:
class NumericRange[T <% Numeric[T]](val lower: T, val upper: T) { ... }
object NumericRange {
def apply[T](lower: T, upper: T)(implicit num: Numeric[T]) = {
import num._
new NumericRange[T](lower, upper)
}
}
... where the line creating the new NumericRange does not compile with these errors:
Multiple markers at this line
- No implicit view available from T => scala.math.Numeric[T].
- not enough arguments for constructor NumericRange: (implicit evidence$1: T => scala.math.Numeric[T])org.reductio.rtree.NumericRange[T]. Unspecified value parameter
evidence$1.
- not enough arguments for constructor NumericRange: (implicit evidence$1: T => scala.math.Numeric[T])org.reductio.rtree.NumericRange[T]. Unspecified value parameter
evidence$1.
- No implicit view available from T => scala.math.Numeric[T].
Numeric is a type class, which means you don't work with instances of Numeric[Double] in this way, but rather that you have a single implicit Numeric[Double] in scope that specifies how to perform numeric operations on Double (see my answer here for a related discussion of Ordering).
So you're looking for an implicit Numeric[T], not a T => Numeric[T]. And fortunately there is one of those in scope for Double, so you can just write:
class NumericRange[T: Numeric](val lower: T, val upper: T) { ... }
Or:
class NumericRange[T](val lower: T, val upper: T)(implicit
ev: Numeric[T]
) { ... }
The "context bound" in the first is just syntactic sugar for the implicit argument in the second.
I'm trying to do the following code:
def sum(e: { def *(x: Double): Double}) = e * 2.0
Problem is, this doesn't work with any numeric classes:
sum(20.0)
<console>:9: error: type mismatch;
found : Double(10.0)
required: AnyRef{def *(x: Double): Double}
algo(10.0)
sum(10)
<console>:9: error: type mismatch;
found : Int(10)
required: AnyRef{def *(x: Double): Double}
algo(10)
Is there something wrong with my code?
Scala's structural type doesn't require AnyRef.
Certainly, the following method declaration doesn't work as expected.
def sum(e: { def *(x: Double): Double }) = e * 2.0
The reason of that is the above code is interpreted as the followings:
def sum(e: AnyRef { def *(x: Double): Double}) = e * 2.0
If you specify Any explicitly, the code works:
scala> def sum(e: Any { def *(x: Double): Double }) = e * 2.0
sum: (e: Any{def *(x: Double): Double})Double
scala> sum(10.0)
res0: Double = 20.0
Your sum method expects a subtype of AnyRef while Double and other numeric types are subtypes of AnyVal. What you should do instead, is to use the Numeric typeclass.
def sum[E:Numeric](e:E) = {
val n = implicitly[Numeric[E]]
n.toDouble(e) * 2
}
Here is a code snippet that tries to reproduce a problem I am facing while implementing an internal DSL:
object testObj {
implicit def foo1[T <% Function1[Int, Int]](fun: T): String = "foo1"
implicit def foo2[T <% Function2[Int, Int, Int]](fun: T): String = "foo2"
def test(arg: String): Unit = {}
test((x:Int) => 5) //Ambiguous implicit conversion error
test((x:Int, y:Int) => 5) //Ambiguous implicit conversion error
}
I am getting ambiguous implicit conversions errors at the shown locations:
<console>:21: error: type mismatch;
found : Int => Int
required: String
Note that implicit conversions are not applicable because they are ambiguous:
both method foo1 in object testObj of type [T](fun: T)(implicit evidence$1: T => (Int => Int))String
and method foo2 in object testObj of type [T](fun: T)(implicit evidence$2: T => ((Int, Int) => Int))String
are possible conversion functions from Int => Int to String
test((x:Int) => 5) //Ambiguous implicit conversion error
^
However commenting one of the implicits does not solve the problem. I am using view bounds since finally I want to chain the implicits. Note that the code snippet given above does not involve implicit chaining.
I was expecting that foo1 implicit conversion would be applicable for the first test application whereas foo2 implicit conversion would be applicable for the second test application.
I don't understand how both the implicits are applicable to both the testfunction applications. Why is this happening and how to make this work?
Edit:
If I don't use view bounds, it works fine as shown below. But I want to use view bounds since I want to chain the implicits the way it is explained in the post How can I chain implicits in Scala?.
implicit def foo1(fun: Function1[Int, Int]): String = "foo1"
implicit def foo2(fun: Function2[Int, Int, Int]): String = "foo2"
def test(arg: String): Unit = {}
test((x:Int) => 5) //No error
test((x:Int, y:Int) => 5) //No error
I'm afraid this won't work. View bounds are just not taken into account when resolving implicits and thus you can't chain implicits. That is be design, because such chaining could create some very unreadable code. The only option I see is to create a new implicit conversion for each possible chain of conversions.