Scala generics type mismatch - scala

In Scala, I'm trying:
import scala.reflect.runtime.{universe => ru}
def foo[T <: Any]: ru.WeakTypeTag[T] = ru.weakTypeTag[String]
But this yields me:
<console>:34: error: type mismatch;
found : reflect.runtime.universe.WeakTypeTag[String]
required: reflect.runtime.universe.WeakTypeTag[T]
def foo[T <: Any]: ru.WeakTypeTag[T] = ru.weakTypeTag[String]
What's up here? I'm relatively sure String should satisfy T's type constraint of deriving from Any...
I guess String failed to bind to the T type parameter. In my use case other types may be returned as well though, and I'm not sure how I could get that answer to the compiler up-front before executing the function, if that's what it's expecting.

Your method foo claims that, for any T <: Any, it returns a WeakTypeTag[T]. That is, if T is (for instance) Int, it should return a WeakTypeTag[Int]. However, your method always returns a WeakTypeTag[String], hence the type mistmatch.

As an alternative you can use wildcard, anyway your type is extended from Any.
def foo[T <: Any]: ru.WeakTypeTag[_] = ru.weakTypeTag[String]
In general the problem is with definition of WeakTypeTag[T] class. It is defined invariantly. So you can not use it in covariant case.
Let's go with an examples.
def bom[T >: String]: List[T] = List[String]() // works fine
def foo[T >: String]: WeakTypeTag[T] = ru.weakTypeTag[String] // compilation fails
I'm defining T as any subtype of String and it works good for Lists but fails for WeakTypeTag that is invariant.
You can define sub type of WeakTypeTag and make it covariant so it will perfectly works.
trait WeakTypeTag1[+X] extends ru.WeakTypeTag {
}
def weakTypeTag1[T](implicit attag: WeakTypeTag1[T]) = attag
def foo[T >: String]: WeakTypeTag1[T] = weakTypeTag1[String] // no it's good

Related

Generic nested type inference works with arity-2 but not with currying

Trying to figure out why the code compiles for nested type inference on method with arity-2 but not with currying.
object Test
{
trait Version
object VersionOne extends Version
trait Request[A <: Version]
trait RequestOne extends Request[VersionOne.type]
case class HelloWorld() extends RequestOne
def test1[A <: Version, T <: Request[A]](t : T, a : A): T = t
def test2[A <: Version, T <: Request[A]](t : T)(a : A): T = t
}
// This works
Test.test1(Test.HelloWorld(), Test.VersionOne)
// This doesn't
Test.test2(Test.HelloWorld())(Test.VersionOne)
test2 fails to compile with the following error:
Error:(22, 73) inferred type arguments [Nothing,A$A96.this.Test.HelloWorld] do not conform to method test2's type parameter bounds [A <: A$A96.this.Test.Version,T <: A$A96.this.Test.Request[A]]
def get$$instance$$res1 = /* ###worksheet### generated $$end$$ */ Test.test2(Test.HelloWorld())(Test.VersionOne)
Looking forward to some insights on the same.
#DmytroMitin already explained why it does fail.
However, you can solve the problem this way, using the Partially-Applied Type trick, together with Generalized Type Constraints.
def test2[T](t: T): Test2PartiallyApplied[T] = new Test2PartiallyApplied(t)
final class Test2PartiallyApplied[T](private val t: T) extends AnyVal {
def apply[A <: Version](a: A)(implicit ev: T <:< Request[A]): T = t
}
Which you can use like this.
Test.test2(Test.HelloWorld())(Test.VersionOne)
// res: HelloWorld = HelloWorld()
Nothing in compile error usually means that some type parameters were not inferred.
Try to specify them explicitly
Test.test2[Test.VersionOne.type, Test.RequestOne](Test.HelloWorld())(Test.VersionOne)
Difference between test1 and test2 is not only in currying. For example, generally in test2(t: ...)(a: ...) type of a can depend on value of t. So for test2 type inferrence is more complicated than for test1.
Scala type inference and multiple arguments list
Type inference with type aliases and multiple parameter list function
Multiple parameter closure argument type not inferred
What's the difference between multiple parameters lists and multiple parameters per list in Scala?

Scala generics not clear to me

class A {
def x(): Unit = {
println("tftf")
}
}
def t[A](x: A): Unit = {
x.x // <- error at this line
}
I get compile error - type mismatch; found : x.type (with underlying type A) required: ?{def x: ?} Note that implicit conversions are not applicable because they are ambiguous: both method any2Ensuring in object Predef of type [A](x: A)Ensuring[A] and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A] are possible conversion functions from x.type to ?{def x: ?}
- t
Can someone explain this in English, please? I am new to Scala.
t's generic parameter named A shadows the class named A.
What you've written is equivalent to:
class A {
def x(): Unit = {
println("tftf")
}
}
def t[B](x: B): Unit = {
x.x // <- error at this line
}
In your example, A is a concrete type (a class). But in the function t[A](x: A): Unit, you're trying to use it as a type parameter. There's nothing generic about it.
A simple example of using generics with the function would be something like:
def t[A](x: A): Unit = println("Here is the parameter x: " + x)
This function will accept any type, and simply print it to the console.
in your def t[A](x: A), A is a generic type parameter and has nothing to do with the class A you defined. you can name it whatever you want, like def t[T](x: T).
what you want to do actually is:
def t[B <: A](x: B): Unit = {
x.x // won't error
}
There are two sources of confusion here:
Your type parameter A shadows class type A.
Type parameter A is unconstrained, which implicitly means [A <: Any], and Any doesn't have the member x. The confusing error message comes from the compiler attempting to apply an implicit conversion from Any to something that has a member x.
You simply want a function that takes a parameter that is a subtype of A, but you don't need a type parameter for this since any subtype of class type A is a valid substitution for class type A as a function parameter.
Hence the solution is simply this:
def t(a: A) {
a.x()
}

Why won't Scala use implicit conversion here?

I'm trying to call this set method documented here, in the Java library jOOQ, with signature:
<T> ... set(Field<T> field, T value)
This Scala line is a problem:
.set(table.MODIFIED_BY, userId)
MODIFIED_BY is a Field<Integer> representing the table column. userId is Int. Predef has an implicit conversion from Int to Integer, so why doesn't it use it? I get this:
type mismatch; found: org.jooq.TableField[gen.tables.records.DocRecord,Integer]
required: org.jooq.Field[Any]
Note: Integer <: Any
(and org.jooq.TableField[gen.tables.records.DocRecord,Integer] <:
org.jooq.Field[Integer]), but Java-defined trait Field is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
Update - About Vinicius's Example
Rather than try to explain this in comments, here is a demonstration that there is no implicit conversion being called when you use a type with covariant parameter, like List[+T]. Let's say I put this code in a file, compile, and run it...
case class Foo(str: String)
object StackOver1 extends App {
implicit def str2Foo(s: String): Foo = {
println("In str2Foo.")
new Foo(s)
}
def test[T](xs: List[T], x: T): List[T] = {
println("test " + x.getClass)
xs
}
val foo1 = new Foo("foo1")
test(List(foo1), "abc")
}
You'll see that it calls test, but never the implicit conversion from String "abc" to Foo. Instead it's picking a T for test[T] that is a common base class between String and Foo. When you use Int and Integer it picks Any, but it's confusing because the runtime representation of the Int in the list is Integer. So it looks like it used the implicit conversion, but it didn't. You can verify by opening a Scala prompt...
scala> :type StackOver1.test(List(new java.lang.Integer(1)), 2)
List[Any]
I don't know anything aboutjOOQ, but I think the issue is that Scala does not understand java generics very well. Try:
scala> def test[T](a : java.util.ArrayList[T], b: T) = { println(a,b) }
scala> val a = new java.util.ArrayList[Integer]()
scala> val b = 12
scala> test(a,b)
<console>:11: error: type mismatch;
found : java.util.ArrayList[Integer]
required: java.util.ArrayList[Any]
Note: Integer <: Any, but Java-defined class ArrayList is invariant in type E.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
test(a,b)
Sounds familiar??
And to fix, just inform the type T to call the method: test[Integer](a,b) works fine.
EDIT:
There a few things involved here:
Erasure -> When compiled the type of the generic will disappear by erasure. The compiler will use Object which Scala, will treat as Any. However a ArrayList[Integer] is not an ArrayList[Any], even though Integer is any. The same way that TableField[gen.tables.records.DocRecord,Integer] is not a Field[Any].
Type inference mechanism -> it will figure out what type T should be and to do that it will use the intersection dominator of the types passed (in our case the first common ancestor). Page 36 of Scala Language Spec, which in our examples above will lead use to Any.
Implicit conversion -> it is the last step and would be called if there was some type to be converted to another one, but since the type of the arguments were determined to be the first common ancestor, there is no need to convert and we will never have a implicit conversion if we don't force the type T.
A example to show how the common ancestor is used to determine T:
scala> def test[T](a: T, b: T): T = a
scala> class Foo
scala> class Boo extends Foo
scala> test(new Boo,new Foo)
res2: Foo = Boo#139c2a6
scala> test(new Boo,new Boo)
res3: Boo = Boo#141c803
scala> class Coo extends Foo
scala> test(new Boo,new Coo)
res4: Foo = Boo#aafc83
scala> test(new Boo,"qsasad")
res5: Object = Boo#16989d8
Summing up, the implicit method does not get called, because the type inference mechanism, determines the types before getting the argument and since it uses the common ancestor, there is no need for a implicit conversion.
Your code produces an error due to erasure mechanism which disappear with the type information that would be important to determine the correct type of the argument.
#RobN, thanks for questioning my answer, I learned a lot with the process.

Overriding abstract type does not work with control abstraction

This question follows the one in Cake pattern with overriding abstract type don't work with Upper Type Bounds. I want to override the abstract type in trait with <:. The previous links gives the solution which consists in changing the order of linearization by writting this: Cake with S in trait S. However, I added a control abstraction named control in the following code. I want to call the method t in it.
trait A {
def ping = println("ping")
}
trait Cake {
type T
}
trait S { this: Cake with S =>
type T <: A with S
def t: T
def s = println("test")
// def control(c: =>T): T = c // compile
// def control(c: =>T): T = c.s // does not compile
def control(c: =>T): T = c.t // does not compile
t.ping
t.s
}
But, this code results in a compilation error that I can't explain
found : S.this.T#T
required: S.this.T
def control(c: =>T): T = c.t
^
What is wrong ?
def control(c: =>T): T
Has return type S#T. Clearly, c has type T as well. Hence, returning c in:
def control(c: =>T): T = c
compiles, while returning c.s does not compile because s has return type of Unit.
c.t does not compile because it has return type of S#T#T.
Thus, the following will compile:
def control(c: =>T): T#T = c.t
As the specifics behind everything that is happening here are a bit non-trivial in general, I suggest you google "type projection" and "path dependent types" for more information.
Essentially what is happening is c has type T, where T <: A with S, so we know T must have all of S's members, one of which is defined as def t: T. But this T is not necessarily the same as our T, so it does not conform when we call c.t in your example. What we want is the T of type T (or equivalently, T's T, or the T of our type member T). Here T#T indicates exactly what we want.

Structural type in method type parameterization in Scala?

Consider the following Scala code (e.g., in REPL)
object A{def foo:Unit = {}}
object B{def foo:Unit = {}}
def bar[T <: Any {def foo: Unit}](param: T*):Unit = param.foreach(x => x.foo)
bar(A, A) // works fine
bar(B, B) // works fine
bar(A, B) // gives error
The first two work fine. The third ones gives an error:
error: inferred type arguments [ScalaObject] do not conform to method bar's type parameter bounds [T <: Any{def foo: Unit}]
Are there any ways to do what I want?
This is usually called structural typing, not duck typing. I edited your title. :)
I think that your problem is caused by defining the type parameter T and then using it in an invariant way. T can only refer to one concrete type, but you have parameters of different types A and B.
This works:
def bar(param: {def foo: Unit}*) = param.foreach(x => x.foo)
Edit: Using a type alias also works:
type T = {def foo: Unit}
def bar(param: T*) = param.foreach(x => x.foo)
This works because the compiler will simply substitute the structural type in place of its alias, T. After the substitution, this example is exactly the same as the one above.