On an earlier SO post I asked how to create use the Aux pattern with a higher kinded type (here, that had a great reply!). Now based on the reply, I am trying to take the abstraction a little but further and have the actual generic parameter be inferred from an argument's type. Trouble is, it seems having trouble differentiating X from X.type. Here's my code:
// The are types that I want to convert to various things
sealed trait ConversionType
trait CaseA extends ConversionType
object CaseA extends CaseA // In this case, convert to an optional
trait CaseB extends ConversionType
object CaseB extends CaseB // In this case, convert to a future etc...
trait Converter[Prefix] {
type Paramd[_]
def create[N](n:N): Paramd[N]
}
// Create the mechanism to convert from the cases, only doing case A for now...
object Converter {
type Aux[Prefix, Ret[_]] = Converter[Prefix] { type Paramd[N] = Ret[N] }
// Shouldn't `Prefix` be automatically inferred?
def apply[Prefix](prefix:Prefix)(implicit p:Converter[Prefix]): Aux[Prefix, p.Paramd] = p
implicit def makeOptionParamd: Aux[CaseA, Option] =
new Converter[CaseA] {
type Paramd[N] = Option[N]
override def create[N](n:N): Paramd[N] = Option[N](n)
}
}
// This works
val v = Converter.apply[CaseA](CaseA).create("test")
// **** This breaks! Why? ****
val vv = Converter.apply(CaseA).create("test")
The following errors occour on the broken line above:
Error:(135, 29) could not find implicit value for parameter p: Test.this.Converter[Test.this.CaseA.type]
val vv = Converter.apply(CaseA).create("test")
Error:(135, 29) not enough arguments for method apply: (implicit p: Test.this.Converter[SchemaMaker.this.CaseA.type])Test.this.Converter.Aux[SchemaMaker.this.CaseA.type,p.Paramd] in object Converter.
Unspecified value parameter p.
val vv = Converter.apply(CaseA).create("test")
So the compiler doesn't connect the dots between the object CaseA and the type CaseA? Is there any way to fix this?
Your object CaseA is at the same time
of type CaseA.type (because it's the singleton object)
of type CaseA (because it extends CaseA)
When you invoke
val vv = Converter.apply(CaseA).create("test")
the inferred type Prefix is CaseA.type (the singleton object type), and no implicit can be found for that type.
Even more explicitly:
val works = Converter.apply(CaseA: CaseA).create("test")
val fails = Converter.apply(CaseA: CaseA.type).create("test")
The absolutely shortest possible change that would force your code to compile would be to add a single - in front of Prefix to make Converter contravariant:
trait Converter[-Prefix] {
type Paramd[_]
def create[N](n:N): Paramd[N]
}
but I'm not sure whether this is what you want, because I don't know what you are attempting to achieve with the all this fancy machinery.
Related
What is the difference between the implicit keyword in Scala 2 and given+using in Scala 3? Is it just that implicit has been split up into two keywords, or are the semantics also different, and if so, how?
For the most part, they are the same. However, implicit is no longer used for multiple different concepts. The docs go into more detail, but here's a summary of them:
Using
When declaring parameters, using is just the same as implicit. However, when explicitly passing an implicit argument, you must use using:
def foo(using bar: Bar) = ???
foo(using Bar()) //Cannot use just foo(Bar()) as you would in Scala 2
You can also have implicit by-name parameters in Scala 3.
Given
Givens are also pretty similar to implicit vals/objects/methods.
One nice thing about them is that they can be anonymous, and the compiler will generate a name for them, which looks something like given_F_X_Y if the type of the given were F[X, Y]. More details here.
Another change is that the type of a given must be written explicitly - it cannot be inferred like for an implicit in Scala 2.
A given without parameters maps to an implicit object. given foo: Foo with {...} becomes just implicit object foo extends Foo {...}.
A given with parameters is akin to an implicit def that takes in only more implicit parameters.
given listOrd[T](using ord: Ord[T]): Ord[List[T]] with { ... }
//^^ this maps to this vv
class listOrd[T](implicit ord: Ord[T]) extends Ord[List[T]] { ... }
final implicit def listOrd[T](implicit ord: Ord[T]): listOrd[T] = new listOrd[T]
A given that is merely an alias becomes an implicit def if it is just a reference, or an implicit lazy val otherwise.
val foo: Foo
given Foo = foo
would become final implicit def given_Foo = foo (note the compiler-generated name), but
given foo: Foo = new Foo()
would turn into final implicit lazy val foo: Foo = new Foo() because new Foo() shouldn't be computed unnecessarily.
Instead of using an implicit def for an implicit conversion from A to B, you can now define a given Conversion[A, B] instance.
You can also still use implicit classes in Dotty, but you can directly define extension methods. While methods inside extensions cannot take their own type parameters, they are easier to use than implicit classes.
An additional change in Scala 3 - summon is a method like implicitly, but it can return a type more specific than the one being requested.
Semantics is also different. In Scala 2 Not can be defined with ambiguity trick
trait Not[A]
object Not {
implicit def default[A]: Not[A] = null
implicit def ambig[A](implicit a: A): Not[A] = null
}
implicitly[Not[Int]] // compiles
implicit val s: String = null
// implicitly[Not[String]] // doesn't compile
But in Scala 3 this doesn't work because ambiguity error is not propagated
trait Not[A]
object Not {
given [A]: Not[A] = null
given [A](using a: A): Not[A] = null
// given ambig[A](using a: A): Not[A] = null
}
summon[Not[Int]] // compiles
given String = null
summon[Not[String]] // compiles
One should use scala.util.NotGiven instead
summon[NotGiven[Int]] // compiles
given String = null
// summon[NotGiven[String]] // doesn't compile
(Tested in 3.0.0-M3-bin-20201211-dbc1186-NIGHTLY)
http://dotty.epfl.ch/docs/reference/contextual/givens.html#negated-givens
http://dotty.epfl.ch/docs/reference/changed-features/implicit-resolution.html
Let's use a real world example. A string parser type class whose implicit instances are created by a function that delegates the creation to a factory.
import scala.reflect.runtime.universe.TypeTag
object Test {
trait Parser[+T] { def parse(input: String): T }
implicit def summonParserOf[T](implicit factory: ParserFactory[T]): Parser[T] = factory.build
trait ParserFactory[T] { def build: Parser[T] }
implicit def summonFactoryOfParsersOf[T](implicit t: TypeTag[T]): ParserFactory[T] =
new ParserFactory[T] {
def build: Parser[T] = new Parser[T] {
def parse(input: String) = {
println("T = " + t.tpe) // this outputs "T = Int" if Parser is non variant, and "T = Nothing" if Parser is covariant on T. Why?
null.asInstanceOf[T]
}
}
}
def main(args: Array[String]): Unit = {
val parserOfInt = implicitly[Parser[Int]]
parserOfInt.parse("")
}
}
The type parameter T received by the factory is Int when Parser is non-variant, and Nothing when it is covariant. Why?
Edit 1:
The factory is not necessary. The replacement occurs before. So the test can be reduced to:
package jsfacile.test
import scala.reflect.runtime.universe.TypeTag
object Probando {
trait Parser[+T] { def parse(input: String): T }
implicit def summonParserOf[T](implicit t: TypeTag[T]): Parser[T] = new Parser[T] {
def parse(input: String): T = {
println("summon parser: T = " + t.tpe) // this outputs "T = Int" if Parser is non variant, and "T = Nothing" if Parser is covariant on T. Why?
null.asInstanceOf[T]
null.asInstanceOf[T]
}
}
def main(args: Array[String]): Unit = {
val parserOfInt = implicitly[Parser[Int]]
parserOfInt.parse("")
}
}
Parser[Nothing] is assignable to Parser[Int], but which is the purpose of choosing the lower bound instead of the upper one?
Edit 2: The answer given by #Dmytro Mitin and the useful comments below, translated to my own words and limited scope of thinking, for future reference to myself.
What stopped me to understand was the wrong idea that, when the implicit value provider is a def with parametrized result type, there is no set of living values from which the compiler has to pick one of. In that case, I thought, it just skips that step (the one that chooses the value with the most specific declared type).
And given the summoner function grants the compiler the power to build a value of any type, why not to fill the implicit parameter with a value that makes him happy. If the implicit parameter demands something assignable to a type T then give it a value of type T. Giving it Nothing, which is assignable to everything, wouldn't be nice nor useful.
The problem with that idea arises when there is more than one summoner providing values assignable to the implicit parameter type. In that case, the only consistent way to decide which summoner to chose is to deduce the set of types of the values they produce, pick a type from said set based on an established criteria (the most specific, for instance), and choose the summoner that produces it.
Scala spec says
If there are several eligible arguments which match the implicit parameter's type, a most specific one will be chosen using the rules of static overloading resolution
https://scala-lang.org/files/archive/spec/2.11/07-implicits.html#implicit-parameters
Since you defined instances like
implicit def summonParserOf[T](implicit t: TypeTag[T]): Parser[T] = ...
for covariant
trait Parser[+T] { ... }
when you look for implicitly[Parser[T]], all summonParserOf[S] (S <: T) are eligible candidates, so the compiler selects the most specific one.
Using reflection, I have determined the runtime type of a thing, t: Type. Now I want to create a new Type of Option[t]. How can I do that?
val t: Type = ...
val optT: Type = ??? // Option of whatever t is
Why I want this: I have a handler function that operates on a Type. At compile time I have something like this:
trait Thing { name: String }
case class BigThing(name: String) extends Thing
case class Stuff[T <: Thing]( id: Int, maybeThing: Option[T] ) // contrived
def handler( t: Type ): Output = {...}
I can reflect that if I have a class of type Stuff, it has a member maybeThing of type Object[T] or even Object[Thing]. At runtime let's say I can determine that a specific object has T = BigThing, so I want to pass Option[BigThing], not Option[T] or Option[Thing] to handler(). That's why I'm trying to create a runtime type of Option[BigThing].
I did try the following but Scala didn't like it:
val newType = staticClass(s"Option[${runtimeTypeTAsString}]")
According to tutorial
there are three ways to instantiate a Type.
via method typeOf on scala.reflect.api.TypeTags, which is mixed into Universe (simplest and most common).
Standard Types, such as Int, Boolean, Any, or Unit are accessible through the available universe.
Manual instantiation using factory methods such as typeRef or polyType on scala.reflect.api.Types, (not recommended).
Using the third way,
import scala.reflect.runtime.universe._
class MyClass
val t: Type = typeOf[MyClass] //pckg.App.MyClass
val mirror = runtimeMirror(ClassLoader.getSystemClassLoader)
val optT: Type = mirror.universe.internal.typeRef(
definitions.PredefModule.typeSignature,
definitions.OptionClass,
List(t)
) // Option[pckg.App.MyClass]
val optT1 : Type = typeOf[Option[MyClass]]
optT =:= optT1 // true
I have some code like this:
sealed trait Foo[A] {
def value: A
}
case class StringFoo(value: String) extends Foo[String]
case class IntFoo(value: Int) extends Foo[Int]
I'd like to have a function which can use the A type given a subtype's type parameter.
// Hypothetical invocation
val i: Int = dostuff[IntFoo](param)
val s: String = dostuff[StringFoo](param)
I can't figure out how to declare dostuff in a way that works. The closest thing I can figure out is
def dostuff[B <: Foo[A]](p: Param): A
But that doesn't work because A is undefined in that position. I can do something like
def dostuff[A, B <: Foo[A]](p: Param): A
But then I have to invoke it like dostuff[String, StringFoo](param) which is pretty ugly.
It seems like the compiler should have all the information it needs to move A across to the return type, how can I make this work, either in standard scala or with a library. I'm on scala 2.10 currently if that impacts the answer. I'm open to a 2.11-only solution if it's possible there but impossible in 2.10
Another option is to use type members:
sealed trait Foo {
type Value
def value: Value
}
case class StringFoo(value: String) extends Foo { type Value = String }
case class IntFoo(value: Int) extends Foo { type Value = Int }
def dostuff[B <: Foo](p: Any): B#Value = ???
// Hypothetical invocation
val i: Int = dostuff[IntFoo](param)
val s: String = dostuff[StringFoo](param)
Note that both solutions mainly work around the syntactic restriction in Scala, that you cannot fix one type parameter of a list and have the compiler infer the other.
As you might know, if you have a parameter of type Foo[A], then you can make the method generic in just A:
def dostuff[A](p: Foo[A]): A = ???
Since that might not always be the case, we can try to use an implicit parameter that can express the relationship between A and B. Since we can't only apply some of the generic parameters to a method call (generic parameter inference is all or nothing), we have to split this into 2 calls. This is an option:
case class Stuff[B <: Foo[_]]() {
def get[A](p: Param)(implicit ev: B => Foo[A]): A = ???
}
You can check the types in the REPL:
:t Stuff[IntFoo].get(new Param) //Int
:t Stuff[StringFoo].get(new Param) //String
Another option along the same lines, but using an anonymous class, is:
def stuff[B <: Foo[_]] = new {
def apply[A](p: Param)(implicit ev: B <:< Foo[A]): A = ???
}
:t stuff[IntFoo](new Param) //Int
Here, I've used apply in stead of get, so you can apply the method more naturally. Also, as suggested in your comment, here I've used <:< in the evidence type. For those looking to learn more about this type of generalized type constraint, you can read more here.
You might also consider using abstract type members instead of generic parameters here. When struggling with generic type inference, this often provides an elegant solution. You can read more about abstract type members and their relationship to generics here.
I'm trying to spin my head around the path-dependent types in Scala's enums while making a Reads/Writes for Play2. Here is the code I have so far, it works, but with an asInstanceOf:
implicit def enumerationReads[T <: Enumeration](implicit t: T): Reads[t.Value] = {
val validationError = ValidationError("error.expected.enum.name", t.values.mkString(", "))
Reads.of[String].filter(validationError)(s ⇒ t.values.exists(v ⇒ v.toString == s)).map(t.withName(_))
}
implicit def enumerationValueSetReads[T <: Enumeration](implicit t: T): Reads[t.ValueSet] =
Reads.seq(enumerationReads[T]).map(seq ⇒ t.ValueSet(seq.asInstanceOf[Seq[t.Value]]: _*))
What can I do to get rid of the asInstanceOf on the last line? I tried typing the enumerationReads as enumerationReads[t.Value], but that doesn't work, the compiler complains in the argument of t.ValueSet that Seq[t.Value] cannot be cast to Seq[t.Value]. Yes, that didn't make sense to me too, until I started to realize these different t's might actually be different, since they are used in a closure.
So, what to do to make my code super-duper asInstanceOf free?
The following code might do the trick:
implicit def enumerationReads(t : Enumeration) : Reads[t.Value] = {
val validationError = ValidationError("error.expected.enum.name", t.values.mkString(", "))
Reads.of[String].filter(validationError)(s ⇒ t.values.exists(v ⇒ v.toString == s)).map(t.withName(_))
}
implicit def enumerationValueSetReads(t: Enumeration): Reads[t.ValueSet] =
Reads.seq(enumerationReads(t : t.type)).map(set => t.ValueSet(set : _*))
or maybe more useful
implicit def enumerationValueSetReads(t: Enumeration): Reads[Set[t.Value]] =
Reads.set(enumerationReads(t : t.type))
An enumeration is already an object (of class Enumeration) so you can use it directly. You don't need to introduce a type T. To type your functions correctly the compiler has to check that types Value and ValueSet both belong to the correct instance of Enumeration (here t). That's called path-dependent types.
In the following code
class T extends Enumeration
object Animals extends T {
val Cow, Pig, Rabbit = Value
}
object Food extends T {
val Rice, Potatoes, Fries = Value
}
Both Animals and Food are instances of T but the types T # Value, Animals.Value and Food.Value are different. T # Value represent any type Value of any instance of T whereas Animals.Value (respectively Food.Value) is the type that belongs to Animals and Animals alone.
In the error "Seq[t.Value] cannot be cast to Seq[t.Value]", which i admit is very confusing, the two occurences of t are different instances. If you call enumerationReads[T] with type T, it considers its argument t to be any, unknown, instance of T. So you lose the track of the instance. That's why you have to call it with type t.type.