Scala type classes resolution - scala

I have seen this solution work on the past, so I'm unsure what I'm doing wrong. Consider the answer of How does type class resolution in scala work?
out of it I did this code:
import org.specs2.mutable.Specification
case class OptionFinder[A](isOption: Boolean)
object OptionFinder extends LowerPriority {
implicit def hitOption[A]: OptionFinder[Option[A]] = OptionFinder(true)
}
trait LowerPriority {
implicit def notOption[A]: OptionFinder[A] = OptionFinder(false)
}
object OptionFinderSpec extends Specification {
"OptionFinder" should {
"find Options" in {
def myFunction[A](value: A)(implicit optionFinder: OptionFinder[A]): Boolean = {
optionFinder.isOption
}
myFunction(5) must beFalse
myFunction(None) must beTrue
myFunction(Some(5)) must beTrue
}
}
}
On my understanding, all tests should pass. For some reason both myFunction(None) must beTrue and myFunction(Some(5)) must beTrue fail
What am I doing wrong?

Compiler is recognizing your parameters in those two cases as None and Some instead of as Option. It's tricky to have an implicit instance for "any A" because then you might be stumbling upon this situation quite often, where you expect some more specific type to be used (e.g. Option[A]), but you accidentally fall back to the implicit for the generic type (in this case A), and compiler cannot really know that it's not what you wanted.
So, this will work:
myFunction(Option.empty) must beTrue
myFunction(Option(5)) must beTrue
This will also work:
implicit def hitOption[A]: OptionFinder[Option[A]] = OptionFinder(true)
implicit def hitOptionN: OptionFinder[None.type] = OptionFinder(true)
implicit def hitOptionS[A]: OptionFinder[Some[A]] = OptionFinder(true)
...
myFunction(None) must beTrue
myFunction(Some(5)) must beTrue
You can blame the design of Option for this one. I'm pretty sure every single Scala developer has at least once encountered the problem "Option expected, but found Some". If you construct them using empty and apply you will be on the safe side.

Related

Context Bound on a Generic Class Using Implicits

I am learning Scala in order to use it for a project.
One thing I want to get a deeper understanding of is the type system, as it is something I have never used before in my other projects.
Suppose I have set up the following code:
// priority implicits
sealed trait Stringifier[T] {
def stringify(lst: List[T]): String
}
trait Int_Stringifier {
implicit object IntStringifier extends Stringifier[Int] {
def stringify(lst: List[Int]): String = lst.toString()
}
}
object Double_Stringifier extends Int_Stringifier {
implicit object DoubleStringifier extends Stringifier[Double] {
def stringify(lst: List[Double]): String = lst.toString()
}
}
import Double_Stringifier._
object Example extends App {
trait Animal[T0] {
def incrementAge(): Animal[T0]
}
case class Food[T0: Stringifier]() {
def getCalories = 100
}
case class Dog[T0: Stringifier]
(age: Int = 0, food: Food[T0] = Food()) extends Animal[String] {
def incrementAge(): Dog[T0] = this.copy(age = age + 1)
}
}
So in the example, there is a type error:
ambiguous implicit values:
[error] both object DoubleStringifier in object Double_Stringifier of type Double_Stringifier.DoubleStringifier.type
[error] and value evidence$2 of type Stringifier[T0]
[error] match expected type Stringifier[T0]
[error] (age: Int = 0, food: Food[T0] = Food()) extends Animal[String]
Ok fair enough. But if I remove the context bound, this code compiles. I.e. if I change the code for '''Dog''' to:
case class Dog[T0]
(age: Int = 0, food: Food[T0] = Food()) extends Animal[String] {
def incrementAge(): Dog[T0] = this.copy(age = age + 1)
}
Now I assumed that this would also not compile, because this type is more generic, so more ambiguous, but it does.
What is going on here? I understand that when I put the context bound, the compiler doesn't know whether it is a double or an int. But why then would an even more generic type compile? Surely if there is no context bound, I could potentially have a Dog[String] etc, which should also confuse the compiler.
From this answer: "A context bound describes an implicit value, instead of view bound's implicit conversion. It is used to declare that for some type A, there is an implicit value of type B[A] available"
Now I assumed that this would also not compile, because this type is more generic, so more ambiguous, but it does.
The ambiguity was between implicits. Both
Double_Stringifier.DoubleStringifier
and anonymous evidence of Dog[T0: Stringifier] (because class Dog[T0: Stringifier](...) is desugared to class Dog[T0](...)(implicit ev: Stringifier[T0])) were the candidates.
(Int_Stringifier#IntStringifier was irrelevant because it has lower priority).
Now you removed the context bound and only one candidate for implicit parameter in Food() remains, so there's no ambiguity. I can't see how the type being more generic is relevant. More generic doesn't mean more ambiguous. Either you have ambiguity between implicits or not.
Actually if you remove import but keep context bound the anonymous evidence is not seen in default values. So it counts for ambiguity but doesn't count when is alone :)
Scala 2.13.2, 2.13.3.
It seems to me (and if I'm wrong I'm hoping #DmytroMitin will correct me), the key to understanding this is with the default value supplied for the food parameter, which makes class Dog both a definition site, requiring an implicit be available at the call site, as well as a call site, requiring an implicit must be in scope at compile time.
The import earlier in the code supplies the implicit required for the Food() call site, but the Dog constructor requires an implicit, placed in ev, from its call site. Thus the ambiguity.

When doing implicit resolution with type parameters, why does val placement matter?

In one file, I have:
trait JsonSchema[T] {
val propertyType: String
override def toString: String = propertyType
}
object JsonSchema {
implicit def stringSchema: JsonSchema[String] = new JsonSchema[String] {
override val propertyType: String = "string"
}
implicit def intSchema: JsonSchema[Int] = new JsonSchema[Int] {
override val propertyType: String = "integer"
}
implicit def booleanSchema: JsonSchema[Boolean] = new JsonSchema[Boolean] {
override val propertyType: String = "boolean"
}
}
In my main file:
case class MetaHolder[T](v: T)(implicit val meta: JsonSchema[T])
object JsonSchemaExample extends App {
println(MetaHolder(3).meta.toString)
println(MetaHolder("wow").meta.toString)
}
That works hunky-dory. Now suppose I do this instead:
case class MetaHolder[T](v: T) {
val meta: JsonSchema[T] = implicitly[JsonSchema[T]]
}
It no longer compiles. Why?
My goal is to modify the anonymous Endpoint classes in the scala Finch library by adding a val meta to everything. I've been able to do this without any fancy-business so far, but now I want to do some fancy implicit resolution with shapeless to provide a JsonSchema definition for arbitrary case classes. My question is how to do this while maintaining backward compatibility. As in: provide the jsonschema meta feature for people who want to opt in, don't change the compilation burden for anyone who does not want to use meta,
If instead I go the first route, with an added implicit parameter, wouldn't that require a special import to be added by everyone? Or am I missing something and would backward compatibility still be maintained?
There is big difference between implicit x: X among parameters and implicitly[X] inside body.
When you say implicitly[X] this means "check now whether in the current scope there is an implicit X".
When you say def foo(...)(implicit x: X) = ... this means "check later when foo is called that in the scope of the call site there will be an implicit X (and for now inside foo just assume without checking that there is)".
class Foo(...)(implicit x: X) is similar to the latter, "check when constructor is called that there will be an implicit X".
Regarding whether users have to import or not. If you put implicits for type X to companion object of X then they will be found automatically (implicits for type X[Y] should be put to companion object of either X or Y). If you put them somewhere else then they have to be imported to the current scope.
In order for implicitly[JsonSchema[T]] to compile, there must be a JsonSchema[T] in the implicit scope, which means that there must be a JsonSchema[T] (or something implicitly convertible to a JsonSchema[T]) passed through as an implicit argument, as you had with:
case class MetaHolder[T](v: T)(implicit val meta: JsonSchema[T])

Strange Scala compiler error when removing a call to a function that has Unit return type, how is this even possible?

Here is a strange situation:
If I comment out the call to feed_usingExplicitTypeClassInstance below, then I get a compiler error.
Very puzzling. Any explanation ?
I mean, I comment out a function call (which returns no value) and then the code does not compile anymore ?
Should this be even possible at all in theory ? In any programming language ?
I mean I comment out something like println("hello") and then the code does not compile anymore ?
Of course it would be understandable if I would comment out a declaration or something, but a call to a function that does not return anything ?
object AnimalFeeder extends App {
def feed_usingExplicitTypeClassInstance[AnimalInstance]
(animalTypeClass: AnimalTypeClass[AnimalInstance])
(food: animalTypeClass.FoodThatAnimalLikes) =
{
animalTypeClass.feed(food)
}
def feed_usingImplicitTypeClassInstance[AnimalInstance, Food]
(food: Food)
(implicit animalTypeClass: AnimalTypeClass.Aux[Food,AnimalInstance]) =
{
animalTypeClass.feed(food)
}
// If I comment out this line, THEN !, I get an error !!!! How ???
feed_usingExplicitTypeClassInstance(AnimalTypeClass.CatInstance)(new CatFood())
feed_usingImplicitTypeClassInstance(new CatFood)
}
trait Food {
def eat(): Unit
}
trait AnimalTypeClass[AnimalInstance] {
type FoodThatAnimalLikes <: Food
def feed(f: FoodThatAnimalLikes) = f.eat()
}
object AnimalTypeClass {
type Aux[Food, Animal] = AnimalTypeClass[Animal] {
type FoodThatAnimalLikes = Food
}
implicit object CatInstance extends AnimalTypeClass[Cat] {
override type FoodThatAnimalLikes = CatFood
}
}
trait Cat
class CatFood extends Food {
override def eat(): Unit = println("meow")
}
This is the error:
Error:(23, 38) could not find implicit value for parameter animalTypeClass: AnimalTypeClass.Aux[CatFood,AnimalInstance]
feed_usingImplicitTypeClassInstance(new CatFood)
Error:(23, 38) not enough arguments for method feed_usingImplicitTypeClassInstance: (implicit animalTypeClass: AnimalTypeClass.Aux[CatFood,AnimalInstance])Unit.
Unspecified value parameter animalTypeClass.
feed_usingImplicitTypeClassInstance(new CatFood)
EDIT:
If I insert the line:
AnimalTypeClass.CatInstance
before:
feed_usingImplicitTypeClassInstance(new CatFood)
then the code compiles again, even if the line
feed_usingExplicitTypeClassInstance(AnimalTypeClass.CatInstance)(new CatFood())
is commented out.
This is a pretty well known issue, where implicits which appear after their usage in the same file and without an explicit type annotation are not found. For that reason it is strongly advised (and this will eventually be enforced) to give all non-local implicits an explicit type annotation. Unfortunately implicit objects are a bit tricky here, because they always act like implicit definitions without type annotation, and it is impossible to give them an explicit type... However last I checked this seemed to be fixed in Dotty for implicit objects.
See also, among others https://github.com/scala/bug/issues/8697
The reason that it does work when you uncomment a call to AnimalTypeClass.CatInstance in your code is that that reference will force the implicit object to be type checked earlier, so its type will be known before its implicit usage.
You have the definition of the implicit value in the same file after the usage of this value. It is not initialized when the compiler looks for an implicit value when you call feed_usingImplicitTypeClassInstance. Calling feed_usingExplicitTypeClassInstance with an explicit reference to this implicit value forces the implicit to initialize, and the compiler can use it in the implicit call.
Possible solutions:
Move the definition of the implicit value to another file.
If the implicit value is in the same file, move its definition above the place where you use it implicitly.

Return type with generic with bounds

I have the following code
import scala.concurrent.Future
class RequestType
class Read extends RequestType
class Write extends RequestType
object Main {
def main(args: Array[String]): Unit = {
}
def dbrequest[T <: RequestType](t: T): Future[T] = {
val dBRequest = new DBRequest
t match {
case r: Read => dBRequest.read(r)
case w: Write => dBRequest.write(w)
}
}
}
class DBRequest {
def read(r: Read): Future[Read] = {
Future(r)
}
def write(w: Write): Future[Write] = {
Future(w)
}
}
read and write method return a Future of type RequestType. If T is bounded and Future is covariant, then why is the compiler failing to conform type of Future[Read] or Future[Write] to Future[T]
Your code will compile with one small change.
def dbrequest[T <: RequestType](t: T): Future[RequestType] = {
So why is it that returning Future[RequestType] works and returning Future[T] doesn't, especially since T is bounded the way it is?
Think of it this way: T is resolved at compile time. With every invocation of dbrequest() the compiler turns T into either Read or Write. The match statement, on the other hand, is resolved at run time. So from the compiler's perspective the match statement returns both Read and Write.
As has been pointed out, you don't really need a type parameter in this code, as presented. The following simplification is equivalent.
def dbrequest(t: RequestType): Future[RequestType] = {
If T is bounded and Future is covariant, then why is the compiler failing to conform type of Future[Read] or Future[Write] to Future[T]
Your code would make sense if T was guaranteed to be Read or Write.
But it could Read with SomeTrait. Or a singleton type (so even making RequestType, Read and Write sealed wouldn't help). Etc. See my answer to Returning subclass of parameterized type in Scala for a solution (just replace Output in that question with Future).

Why does an implicit conversion on the constructor require 'this'?

Consider the following typical Scala 'pimp' code:
class PimpedA(a:A){
def pimp() = "hi"
}
implicit def pimpA(a:A) = new PimpedA(a)
new A(){
pimp() //<--- does not compile
}
However, changing it to:
new A(){
this.pimp()
}
Makes it work.
Shouldn't it be the same to the Scala compiler?
EDIT : Is there any solution that can make it work without having to add the this.?
Not at all. For it to work, pimp needs to be either an object or an imported member of a value, and it is neither. A class has an "implicit" import this._. It has not a mechanism that auto-prepends this to stuff to see if it compiles.
In this case you should give compiler a hint that pimp() is not a random function. When you write
this.pimp()
compiler know there isn't pimp function on class A so it's an error and before giving up it searches implicit conversion in scope and finds it.
pimpA(this).pimp()
And when you just call pimp() compiler doesn't know what object to pass to the pimpA(a: A) implicit function.
UPDATE
It is hard to understand what is your goal. I can only suggest to make PimpedA a typeclass (Pimp[T] in this example).
trait Pimp[T] {
def action(p: T): String
}
implicit object PimpA extends Pimp[A] {
override def action(p: A) = "some actions related to A"
}
def pimp[T: Pimp](p: T) = implicitly[Pimp[T]].action(p)
class A {
val foo = pimp(this)
}
scala> new A foo
res2: String = some actions related to A