What changes in type inference will Scala 3 bring? Currently documentation simply states TODO. For example,
Weak conformance
Scala 2.13
scala> val i: Int = 42
val i: Int = 42
scala> val c: Char = 'a'
val c: Char = a
scala> List(i,c)
val res0: List[Int] = List(42, 97)
Scala 3 (dotty 0.24.0-RC1)
scala> val i: Int = 42
val i: Int = 42
scala> val c: Char = 'a'
val c: Char = a
scala> List(i,c)
val res0: List[AnyVal] = List(42, a)
Equality
Scala 2.13
scala> 42 == Some(42)
^
warning: comparing values of types Int and Some[Int] using `==` will always yield false
val res2: Boolean = false
Scala 3
scala> 42 == Some(42)
1 |42 == Some(42)
|^^^^^^^^^^^^^^
|Values of types Int and Some[Int] cannot be compared with == or !=
So as for your Equality example it is actually caused by the new Multiversal Equality which pretty much means that if you have an Eql[A, B] where A is B then type A can only be compared to things it has an Eql instance for them (of the form Eql[A, C] or Eql[C, A]).
In terms of general type inference for scala 3, the main things are:
Union Types: We can now represent union types and expressions like
if (condition) 1 else "1"
should be of inferred as of type Int | String.
Explicit Nulls: One of the new uses for union types is a way to describe nullable types, so for example we could write such a code in Java:
public String getUser(int id) {
if (id == 0) {
return "Admin";
}
return null;
}
And also in scala 2 we could write:
def getUser(id: Int): String = if (id == 0) return "Admin" else null
But in scala 3 such a method will also have to be declared as of type String | Null to represent its nullability, and will not compile by default in newer versions of scala 3.
When working with Java it gets more complicated so if you want to know more about it I suggest reading in the link.
GADT: Similar to how #functionalInterface works in java we know have GADTs.
That means that if you were to have a trait with one unimplemented method:
trait Fooable {
def foo(): Unit
}
You could create an instance of it by passing a lambda with that signature, so in this example:
val fooable: Fooable = () => print("Fooing")
There are a few more, including Context Functions, Implicit Conversions and Parameter untupling but those are the main ones.
Inferred types are now propagated through the remainder of the single parameter list, which means using multiple parameter lists to aid inference might not be necessary.
Scala 2.13
scala> def f[T](i: T, g: T => T) = g(i)
def f[T](i: T, g: T => T): T
scala> f(41, x => x + 1)
^
error: missing parameter type
Scala 3
scala> def f[T](i: T, g: T => T) = g(i)
def f[T](i: T, g: T => T): T
scala> f(41, x => x + 1)
val res0: Int = 42
I guess this change might be related to Allow inter-parameter dependencies #2079
Better inference when type parameters are not surfaced in terms
Scala 2.13
scala> def f[F <: List[A], A](as: F) = as
def f[F <: List[A], A](as: F): F
scala> f(List(42))
^
error: inferred type arguments [List[Int],Nothing] do not conform to method f's type parameter bounds [F <: List[A],A]
^
error: type mismatch;
found : List[Int]
required: F
Scala 3
scala> def f[F <: List[A], A](as: F) = as
def f[F <: List[A], A](as: F): F
scala> f(List(42))
val res0: List[Int] = List(42)
Related
I'm trying to write some generic testing software for various types using a parameterized base class. I get match errors though on code which I don't believe should be possible.
abstract class AbstractTypeTest[TestType: ClassTag, DriverType <: AnyRef : ClassTag](
def checkNormalRowConsistency(
expectedKeys: Seq[TestType],
results: Seq[(TestType, TestType, TestType)]) {
val foundKeys = results.filter {
case (pkey: TestType, ckey: TestType, data: TestType) => expectedKeys.contains(pkey)
case x => throw new RuntimeException(s"${x.getClass}")
}
foundKeys should contain theSameElementsAs expectedKeys.map(x => (x, x, x))
}
}
An extending class specifies the parameter of TypeTest but this code block throws Runtime Exceptions (because we don't match what I believe should be the only allowed type here)
The output of the above code with some extended types works but with others it does not, in this case I'm extending this class with TestType --> Int
[info] java.lang.RuntimeException: class scala.Tuple3
I can remove the type on the filter and the ScalaTest check works perfectly but I'd like to understand why the MatchError occurs.
If you're on Scala 2.10, then
ClassTag based pattern matching fails for primitives
scala> import reflect._
import reflect._
scala> def f[A: ClassTag](as: Seq[(A,A,A)]) = as filter {
| case (x: A, y: A, z: A) => true ; case _ => false }
f: [A](as: Seq[(A, A, A)])(implicit evidence$1: scala.reflect.ClassTag[A])Seq[(A, A, A)]
scala> val vs = List((1,2,3),(4,5,6))
vs: List[(Int, Int, Int)] = List((1,2,3), (4,5,6))
scala> f(vs)
res0: Seq[(Int, Int, Int)] = List()
versus 2.11
scala> f[Int](vs)
res4: Seq[(Int, Int, Int)] = List((1,2,3), (4,5,6))
Update (2018): my prayers were answered in Dotty (Type Lambdas), so the following Q&A is more "Scala 2.x"-related
Just a simple example from Scala:
scala> def f(x: Int) = x
f: (x: Int)Int
scala> (f _)(5)
res0: Int = 5
Let's make it generic:
scala> def f[T](x: T) = x
f: [T](x: T)T
scala> (f _)(5)
<console>:9: error: type mismatch;
found : Int(5)
required: Nothing
(f _)(5)
^
Let's look at eta-expansion of polymorphic method in Scala:
scala> f _
res2: Nothing => Nothing = <function1>
Comparison with Haskell:
Prelude> let f x = x
Prelude> f 5
5
Prelude> f "a"
"a"
Prelude> :t f
f :: t -> t
Haskell did infer correct type [T] => [T] here.
More realistic example?
scala> identity _
res2: Nothing => Nothing = <function1>
Even more realistic:
scala> def f[T](l: List[T]) = l.head
f: [T](l: List[T])T
scala> f _
res3: List[Nothing] => Nothing = <function1>
You can't make alias for identity - have to write your own function. Things like [T,U](t: T, u: U) => t -> u (make tuple) are impossible to use as values. More general - if you want to pass some lambda that rely on generic type (e.g. uses generic function, for example: creates lists, tuples, modify them in some way) - you can't do that.
So, how to solve that problem? Any workaround, solution or reasoning?
P.S. I've used term polymorphic lambda (instead of function) as function is just named lambda
Only methods can be generic on the JVM/Scala, not values. You can make an anonymous instance that implements some interface (and duplicate it for every type-arity you want to work with):
trait ~>[A[_], B[_]] { //exists in scalaz
def apply[T](a: A[T]): B[T]
}
val f = new (List ~> Id) {
def apply[T](a: List[T]) = a.head
}
Or use shapeless' Poly, which supports more complicated type-cases. But yeah, it's a limitation and it requires working around.
P∀scal is a compiler plugin that provides more concise syntax for encoding polymorphic values as objects with a generic method.
The identity function, as a value, has type ∀A. A => A. To translate that into Scala, assume a trait
trait ForAll[F[_]] {
def apply[A]: F[A]
}
Then the identity function has type ForAll[λ[A => A => A]], where I use the kind-projector syntax, or, without kind-projector:
type IdFun[A] = A => A
type PolyId = ForAll[IdFun]
And now comes the P∀scal syntactic sugar:
val id = Λ[Α](a => a) : PolyId
or equivalently
val id = ν[PolyId](a => a)
("ν" is the Greek lowercase letter "Nu", read "new")
These are really just shorthands for
new PolyId {
def apply[A] = a => a
}
Multiple type parameters and parameters of arbitrary kinds are supported by P∀scal, but you need a dedicated variation on the above ForAll trait for each variant.
I really like #Travis Brown 's solution:
import shapeless._
scala> Poly(identity _)
res2: shapeless.PolyDefns.~>[shapeless.Id,shapeless.Id] = fresh$macro$1$2$#797aa352
-
scala> def f[T](x: T) = x
f: [T](x: T)T
scala> Poly(f _)
res3: shapeless.PolyDefns.~>[shapeless.Id,shapeless.Id] = fresh$macro$2$2$#664ea816
-
scala> def f[T](l: List[T]) = l.head
f: [T](l: List[T])T
scala> val ff = Poly(f _)
ff: shapeless.PolyDefns.~>[List,shapeless.Id] = fresh$macro$3$2$#51254c50
scala> ff(List(1,2,3))
res5: shapeless.Id[Int] = 1
scala> ff(List("1","2","3"))
res6: shapeless.Id[String] = 1
Poly constructor (in some cases) will give you eta-expansion into Shapeless2 Poly1 function, which is (more-less) truly generic. However it doesn't work for multi-parameters (even with multi type-parameters), so have to "implement" Poly2 with implicit + at approach (as #som-snytt suggested), something like:
object myF extends Poly2 {
implicit def caseA[T, U] = at[T, U]{ (a, b) => a -> b}
}
scala> myF(1,2)
res15: (Int, Int) = (1,2)
scala> myF("a",2)
res16: (String, Int) = (a,2)
P.S. I would really want to see it as a part of language.
It seems to do this you will need to do a bit type hinting to help the Scala type inference system.
def id[T] : T => T = identity _
So I guess if you try to pass identity as a parameter to a function call and the types of that parameter are generic then there should be no problem.
I want to define a function f that takes another function g. We require g to take take n Doubles (for some fixed n) and return a Double. The function call f(g) should return the specific value of n.
For example, f(Math.max) = 2 since Math.sin has type (Double, Double) => Double, and f(Math.sin) = 1 since Math.sin has type Double => Double.
How can I define f using Scala generics?
I've tried several forms without success. For example:
def f[A <: Product](g: Product => Double) = {...}
This doesn't work since we cannot extract the value of n at compile time, and cannot constrain the A to contain only Double values.
There is a pattern called Magnet Pattern, created by the Spray team. It does exectly what you want
This was a good excuse for me to look into Shapeless, something I always wanted to do at some point :)
$ git clone git#github.com:milessabin/shapeless.git
...
$ cd shapeless
(1)
Shapeless provides some abstractions over arity, and especially the representation as heterogeneous list (HList). A function of arbitrary arity can be seen as FnHList (a function that takes an HList as argument).
$ sbt shapeless-core/console
scala> import shapeless._
import shapeless._
scala> def isFunction[A](fun: A)(implicit fnh: FnHLister[A]) {}
isFunction: [A](fun: A)(implicit fnh: shapeless.FnHLister[A])Unit
scala> isFunction(math.sqrt _)
scala> isFunction(math.random _)
(2)
Now let's require that the function returns a Double:
scala> def isFunReturningDouble[A](fun: A)(implicit fnh: FnHLister[A] { type Result = Double }) {}
isFunReturningDouble: [A](fun: A)(implicit fnh: shapeless.FnHLister[A]{type Result = Double})Unit
scala> isFunReturningDouble(math.sqrt _)
scala> isFunReturningDouble(math.signum _)
<console>:12: error: could not find implicit value for parameter fnh: shapeless.FnHLister[Int => Int]{type Result = Double}
isFunReturningDouble(math.signum _)
^
(3)
The LUBConstraint type class can witness the upper bound of the argument list:
scala> def isValidFun[A, B <: HList](fun: A)(implicit fnh: FnHLister[A] { type Result = Double; type Args = B }, lub: LUBConstraint[B, Double]) {}
isValidFun: [A, B <: shapeless.HList](fun: A)(implicit fnh: shapeless.FnHLister[A]{type Result = Double; type Args = B}, implicit lub: shapeless.LUBConstraint[B,Double])Unit
scala> isValidFun(math.random _)
scala> isValidFun((i: Int) => i.toDouble)
<console>:12: error: could not find implicit value for parameter lub: shapeless.LUBConstraint[B,Double]
isValidFun((i: Int) => i.toDouble)
^
(4)
Now we still need to extract the arity somehow. On the type level this would be Length which is provided for HList. To get a runtime value, another type class ToInt is needed.
Here is the final function:
import shapeless._
def doubleFunArity[A, B <: HList, C <: Nat](fun: A)(implicit
fnh: FnHLister[A] { type Result = Double; type Args = B },
lub: LUBConstraint[B, Double],
len: Length[B] { type Out = C },
res: ToInt[C]
): Int = res()
Test:
scala> doubleFunArity(math.sqrt _)
res15: Int = 1
scala> doubleFunArity(math.random _)
res16: Int = 0
scala> val g: (Double, Double) => Double = math.max _
g: (Double, Double) => Double = <function2>
scala> doubleFunArity(g)
res17: Int = 2
Note that unfortunately many math operations are overloaded, and without strong type constraint, Scala will not give you the Double version automatically, but will use the Int version for some reason:
scala> math.max _
res18: (Int, Int) => Int = <function2>
So I need the indirection math.max _: ((Double, Double) => Double) to make this work.
Not saying that this is the best way to do it in your concrete case, but I think it was a fun exploration.
Probably the easiest solution is to use overloading as
def f(g: () => Double) = 0;
def f(g: (Double) => Double) = 1;
def f(g: (Double, Double) => Double) = 2;
def f(g: (Double, Double, Double) => Double) = 2;
// ...
println(f(Math.pow _));
println(f(Math.sin _));
(You can't check function argument/return types at run time due to type erasure, so I believe you can't create a fully generic function that would satisfy your requirements.)
I've been using scala for a while now and I thought I was really starting to understand everything (well, most things...), but I found myself confused by a number of the method definitions in the Map class. I know how foldLeft, etc work, but what I'm confused about is the type parameters used in the Map functions. Let's use foldLeft as an example:
foldLeft [B] (z: B)(op: (B, (A, B)) ⇒ B) : B
The definition for the Map trait itself takes two type parameters 'A' and 'B' (e.g. Map[A,+B]). From what I can tell, when you define a type parameter for a method using the same name as one of the type parameters for the class/trait, it overrides the class/trait value. Take this definition of Foo as an example:
class Foo[A : Manifest, B : Manifest] {
def isAString() = manifest[A] == manifest[String]
def isAInt() = manifest[A] == manifest[Int]
def isBString() = manifest[B] == manifest[String]
def isBInt() = manifest[B] == manifest[Int]
def nowIsBString[B : Manifest] = manifest[B] == manifest[String]
}
scala> val f = new Foo[String,Int]
f: Foo[String,Int] = Foo#7bacb41
scala> f.isAString
res290: Boolean = true
scala> f.isAInt
res291: Boolean = false
scala> f.isBString
res292: Boolean = false
scala> f.isBInt
res293: Boolean = true
scala> f.nowIsBString[String]
res294: Boolean = true
scala> f.nowIsBString[Int]
res295: Boolean = false
So in the foldLeft definition, 'B' comes from the method definition and 'A' comes from the trait definition. For example:
val xm = Map("test" -> 1, "test2" -> 2)
scala> val foldFn = (z: Int, kv: (String, Int)) => z + kv._2
foldFn: (Int, (String, Int)) => Int = <function2>
scala> m.foldLeft(0)(foldFn)
res298: Int = 3
This is as expected as 'B' for the function matches 'B' for the trait, but what if I change the 'B' type for the function to String instead of Int:
scala> val foldFn = (z: String, kv: (String, String)) => z + kv._2
foldFn: (String, (String, String)) => java.lang.String = <function2>
scala> m.foldLeft("")(foldFn)
<console>:19: error: type mismatch;
found : (String, (String, String)) => java.lang.String
required: (java.lang.String, (java.lang.String, Int)) => java.lang.String
m.foldLeft("")(foldFn)
So let's change the kv parameter to (String, Int):
scala> val foldFn = (z: String, kv: (String, Int)) => z + kv._2
foldFn: (String, (String, Int)) => java.lang.String = <function2>
scala> m.foldLeft("")(foldFn)
res299: java.lang.String = 12
Unlike my Foo example, in this case the Map's 'B' value is taking precedence over the functions definition, but only for the kv parameter. What I would have expected is to see a foldLeft defined as follows:
foldLeft[C] (z: C)(op: (C, (A, B)) => C): C
That would be more clear to me, but it is not defined this way. So does anyone know the rules for when a methods parameter will override a trait/class parameter and when it will not?
Scala is the same as Java in this respect, and the following from the "Names" chapter of the Java specification applies:
A declaration d of a type named n shadows the declarations of any
other types named n that are in scope at the point where d occurs
throughout the scope of d.
So the type parameter for a method will always shadow a class or trait type parameter with the same name. Your Foo example demonstrates this fact.
The apparent counterexample you're seeing in the case of Map's foldLeft is just an unpleasant artifact of the current version of Scaladoc, as is pointed out in the answers to the question you've linked. foldLeft isn't defined in the Map trait, but in TraversableOnce, where there isn't a trait type parameter named B at all.
In general shadowing the type parameter of a trait or class in a method is a really bad idea, of course.
I have an heterogeneous List like the following one:
val l = List(1, "One", true)
and I need to filter its objects by extracting only the ones belonging to a given Class. For this purpose I wrote a very simple method like this:
def filterByClass[A](l: List[_], c: Class[A]) =
l filter (_.asInstanceOf[AnyRef].getClass() == c)
Note that I am obliged to add the explicit conversion to AnyRef in order to avoid this compilation problem:
error: type mismatch;
found : _$1 where type _$1
required: ?{val getClass(): ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method any2stringadd in object Predef of type (x: Any)scala.runtime.StringAdd
and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
are possible conversion functions from _$1 to ?{val getClass(): ?}
l filter (_.getClass() == c)
However in this way the invocation of:
filterByClass(l, classOf[String])
returns as expected:
List(One)
but of course the same doesn't work, for example, with Int since they extends Any but not AnyRef, so by invoking:
filterByClass(l, classOf[Int])
the result is just the empty List.
Is there a way to make my filterByClass method working even with Int, Boolean and all the other classes extending Any?
The collect method already does what you want. For example to collect all Ints in a collection you could write
xs collect { case x: Int => x }
This of course only works when you hardcode the type but as primitives are handled differently from reference types it is actually better to do so. You can make your life easier with some type classes:
case class Collect[A](collect: PartialFunction[Any,A])
object Collect {
implicit val collectInt: Collect[Int] = Collect[Int]({case x: Int => x})
// repeat for other primitives
// for types that extend AnyRef
implicit def collectAnyRef[A <: AnyRef](implicit mf: ClassManifest[A]) =
Collect[A]({ case x if mf.erasure.isInstance(x) => x.asInstanceOf[A] })
}
def collectInstance[A : Collect](xs: List[_ >: A]) =
xs.collect(implicitly[Collect[A]].collect)
Then you can use it without even passing a Class[A] instance:
scala> collectInstance[Int](l)
res5: List[Int] = List(1)
scala> collectInstance[String](l)
res6: List[String] = List(One)
Using isInstanceOf:
scala> val l = List(1, "One", 2)
l: List[Any] = List(1, One, 2)
scala> l . filter(_.isInstanceOf[String])
res1: List[Any] = List(One)
scala> l . filter(_.isInstanceOf[Int])
res2: List[Any] = List(1, 2)
edit:
As the OP requested, here's another version that moves the check in a method. I Couldn't find a way to use isInstanceOf and so I changed the implementation to use a ClassManifest:
def filterByClass[A](l: List[_])(implicit mf: ClassManifest[A]) =
l.filter(mf.erasure.isInstance(_))
Some usage scenarios:
scala> filterByClass[String](l)
res5: List[Any] = List(One)
scala> filterByClass[java.lang.Integer](l)
res6: List[Any] = List(1, 2)
scala> filterByClass[Int](l)
res7: List[Any] = List()
As can be seen above, this solution doesn't work with Scala's Int type.
The class of an element in a List[Any] is never classOf[Int], so this is behaving as expected. Your assumptions apparently leave this unexpected, but it's hard to give you a better way because the right way is "don't do that."
What do you think can be said about the classes of the members of a heterogenous list? Maybe this is illustrative. I'm curious how you think java does it better.
scala> def f[T: Manifest](xs: List[T]) = println(manifest[T] + ", " + manifest[T].erasure)
f: [T](xs: List[T])(implicit evidence$1: Manifest[T])Unit
scala> f(List(1))
Int, int
scala> f(List(1, true))
AnyVal, class java.lang.Object
scala> f(List(1, "One", true))
Any, class java.lang.Object
This worked for me. Is this what you want?
scala> val l = List(1, "One", true)
l: List[Any] = List(1, One, true)
scala> l filter { case x: String => true; case _ => false }
res0: List[Any] = List(One)
scala> l filter { case x: Int => true; case _ => false }
res1: List[Any] = List(1)
scala> l filter { case x: Boolean => true; case _ => false }
res2: List[Any] = List(true)
Despite my solution could be less elegant than this one I find mine quicker and easier. I just defined a method like this:
private def normalizeClass(c: Class[_]): Class[_] =
if (classOf[AnyRef].isAssignableFrom((c))) c
else if (c == classOf[Int]) classOf[java.lang.Integer]
// Add all other primitive types
else classOf[java.lang.Boolean]
So by using it in my former filterByClass method as it follows:
def filterByClass[A](l: List[_], c: Class[A]) =
l filter (normalizeClass(c).isInstance(_))
the invocation of:
filterByClass(List(1, "One", false), classOf[Int])
just returns
List(1)
as expected.
At the end, this problem reduces to find a map between a primitive and the corresponding boxed type.
Maybe a help can arrive from scala.reflect.Invocation (not included in the final version of 2.8.0), the getAnyValClass function in particular (here slightly edited)
def getAnyValClass(x: Any): java.lang.Class[_] = x match {
case _: Byte => classOf[Byte]
case _: Short => classOf[Short]
case _: Int => classOf[Int]
case _: Long => classOf[Long]
case _: Float => classOf[Float]
case _: Double => classOf[Double]
case _: Char => classOf[Char]
case _: Boolean => classOf[Boolean]
case _: Unit => classOf[Unit]
case x#_ => x.asInstanceOf[AnyRef].getClass
}
With this function the filter is as easy as
def filterByClass[T: Manifest](l:List[Any]) = {
l filter (getAnyValClass(_) == manifest[T].erasure)
}
and the invocation is:
filterByClass[Int](List(1,"one",true))