Scala generics not clear to me - scala

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()
}

Related

How to get the parameter of a type constructor in Scala?

I'm looking for a way to "unwind" type aliases.
In the following example, only 'O' has a type alias defined in the second type aliasing line.
type CodebookDetails = List[(String, List[String])]
type O[I] = CodebookDetails
requestDecodeIterable[I, O](request)
Is it possible to get I in a similar way, or does one just have to copy and paste types like this?:
requestDecodeIterable[(String, List[String]), List](request)
You could use shapeless's the macro:
// Typelevel function unapplies unary type constructors:
// F[A] => (F, A)
// I think I recall seeing it somewhere in shapeless, but I can't find it,
// so I implemented it myself
sealed trait Unapp1[T] { type F[_]; type A; implicit def eq: F[A] =:= T }
object Unapp1 {
type Aux[T0, F0[_], A0] = Unapp1[T0] { type F[X] = F0[X]; type A = A0 }
implicit def source[F0[_], A0]: Aux[F0[A0], F0, A0] = new Unapp1[F0[A0]] {
type F[X] = F0[X]
type A = A0
override def eq: F[A] =:= F0[A0] = implicitly
}
def apply[T](implicit unapp: Unapp1[T]): unapp.type = unapp
}
// the.`tpe` looks up the implicit value of type tpe and gives it a stable path
// suitable for type selection
requestDecodeIterable[the.`Unapp1[CookbookDetails]`.A, the.`Unapp1[CookbookDetails]`.F](request)
It's not really an improvement in this case, especially because I think the inferencer can just do it itself, but it might have other uses.
EDIT: Found it: it's called Unpack1 in shapeless.

Can not find implicit conversion for a parameter of method with lower type bound

I have this code:
class Action[T]
class Insert[T] extends Action[T]
case class Quoted[T]()
implicit def unquote[T](q: Quoted[T]): T = {
throw new Exception("Success")
}
def test[A <: Action[_]](a: A): A = {
return a
}
try {
test[Insert[String]](Quoted[Insert[String]])
test(unquote(Quoted[Insert[String]]))
// test(Quoted[Insert[String]]) // does not compile
} catch {
case e: Exception => print(e.getMessage())
}
Scalafiddle
Commented line fails during compilation with:
error: inferred type arguments [ScalaFiddle.Quoted[ScalaFiddle.Insert[String]]] do not conform to method test's type parameter bounds [A <: ScalaFiddle.Action[_]]
test(Quoted[Insert[String]])
error: type mismatch;
found : ScalaFiddle.Quoted[ScalaFiddle.Insert[String]]
required: A
test(Quoted[Insert[String]])
Is there any way to make it compile without specifying type parameter or explicitly using conversion function as in previous two lines?
Perhaps you could overload the test method like so:
def test[A, B <: Action[_]](a: A)(implicit f: A => B): B = f(a)
Then this does compile and work:
test(Quoted[Insert[String]])
I'm not positive about an explanation for why this is necessary, though. Perhaps if you're not explicit about the type parameter, it gets inferred and checked against bounds before any implicit conversions are applied. In your example, the implicit conversion search is triggered by a mismatch between the type parameter and the argument.

aliasing proper type as existential type (why it compiles?)

Why can I do the following:
class A
type M[_] = A
I would expect I can only alias type that expects one type parameter, for example a List[_], but it works also with plain classes.
If I create a method:
def foo(m: M[_]) = m
and call it with wrong parameter:
scala> foo("a")
<console>:15: error: type mismatch;
found : String("a")
required: M[_]
(which expands to) A[]
foo("a")
I get such error. What is the meaning of A[]?
Going further, how to explain this:
scala> type M[_, _] = A
<console>:12: error: _ is already defined as type _
type M[_, _] = A
Is there a way to assure that what I put on the right hand side of my alias will be a parametrized type?
type M[_] = A is the same as type M[X] = A: a constant function on types. M[X] is A whatever X is: M[Int] is A, M[String] is A, M[Any] is A, etc. _ in this case is just an identifier (which explains the error for type M[_, _] as well).
Of course, in def foo(m: M[_]) = m, M[_] is an existential type: M[T] forSome { type T }. I don't know why Scala says it expands to A[] in the error message, though; this may be a bug. You can check it's the same type as A by calling
scala> implicitly[M[_] =:= A]
res0: =:=[A[],A] = <function1>
Is there a way to assure that what I put on the right hand side of my alias will be a parametrized type?
You can declare an abstract member type with higher-kind
trait Foo { type M[_] }
and it can only be implemented by parametrized types:
class Bar1 extends Foo { type M = Int } // fails
class Bar2 extends Foo { type M[X] = List[X] } // works
Of course, as mentioned in the first paragraph, M in type M[X] = Int is parametrized, and I don't think there is a way to rule it out.

Scala generics type mismatch

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

Why can a non-applicable implicit conversion introduce ambiguity?

The setup for this example (Scala 2.10.3):
trait S[A]
trait T[A]
implicit class X[A : S](a: A) { def foo() { } }
implicit class Y[A : T](a: A) { def foo() { } }
implicit object I extends S[String]
This compiles:
new X("").foo()
This doesn't:
new Y("").foo()
because there is no implicit T[String].
could not find implicit value for evidence parameter of type T[String]
new Y("").foo()
^
Therefore, I would assume that scalac could unambiguously apply the implicit conversion from String to X:
"".foo()
But instead we get:
type mismatch;
found : String("")
required: ?{def foo: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method X of type [A](a: A)(implicit evidence$1: S[A])X[A]
and method Y of type [A](a: A)(implicit evidence$1: T[A])Y[A]
are possible conversion functions from String("") to ?{def foo: ?}
"".foo()
^
Is this intentional? Is scalac not supposed to consider whether each conversion would actually work when it enumerates the candidates?
My nonacademic view is that implicit is by design not meant to work everytime it seems that it should work. I think it's a good idea otherwise you could easily get into an implicit hell. You could extend your example by adding more layers of implicit conversions. It would be hard to tell which function is actually called just by looking at the code. There are well-defined rules, but I remember simply that if it's not obvious from the code what's going on, it doesn't work.
I would say that your code breaks One-at-a-time Rule which leads to breaking the Non-Ambiguity Rule. A : S is just a syntactic sugar, and can be rewritten to:
implicit class X[A](a: A)(implicit e: S[A]) { def foo() { } }
implicit class Y[A](a: A)(implicit e: T[A]) { def foo() { } }
Without resolution of the "second" implicit level (method argument e) both classes X and Y look the same to the compiler and therefore are ambiguous. As the linked document says: "For sanity's sake, the compiler does not insert further implicit conversions when it is already in the middle of trying another implicit."