Scala Type matching function inside a trait body - scala

I'm new to Scala and working through this book (Function Programming in Scala). One of the exercises involves replicating the Option trait and its functions. However I'm having a problem compiling my solution in the REPL.
sealed trait Nullable[+A] {
def get[B >: A](default: => B) : B = this match {
case Value(v) => v
case Null => default
}
}
case class Value[+A](value: A) extends Nullable[A]
case object Null extends Nullable[Nothing]
REPL error details:
error: constructor cannot be instantiated to expected type;
found : Value[A(in class Value)]
required: Nullable[A(in trait Nullable)]
case Value(v) => v
error: pattern type is incompatible with expected type;
found : Null.type
required: Nullable[A]
case Null => default
Based on those errors I have a nagging feeling that the compiler can't infer that the type of this (being pattern matched on) is a Nullable.
I've tried this block of code on this online Scala utility and it seems to compile and run. The only difference I can see is that the online tool is using Scala version 2.10.3 and I'm running 2.11.7
So I'm not sure if this is environmental or if I need to help the Scala compiler here. I have also tried to compile the answer from the book's authors and I get the same errors.
Any help would be much appreciated.

Posting an answer in case someone else has a similar issue.
Use the REPL :paste command to load the .scala file, instead of the :load command.
Thank you to #noah and #jwvh for the help.

Related

Scala: type hint for lambda

I'm refreshing scala. This looks very simple to me but I can't get it to run:
import java.nio.file.{FileSystems, Files}
object ScalaHello extends App {
val dir = FileSystems.getDefault.getPath("/home/intelli/workspace")
Files.walk(dir).map(_.toFile).forEach(println)
}
It throws error at the mapping lambda:
argument expression's type is not compatible with formal parameter type;
found : java.util.function.Function[java.nio.file.Path,java.io.File]
required: java.util.function.Function[_ >: java.nio.file.Path, _ <: ?R]
I suspect it has something to do with providing type hints for the lambda but I can't find anything surfing Google. Much appreciated
Note that Files.walk returns a Java Stream, so map and forEach come from Java.
Assuming you are using Scala 2.12, your code will work if you either:
Update Scala version to 2.13 (no need to make any other changes in this case)
Specify return type of map:
Files.walk(dir).map[File](_.toFile).forEach(println)
Convert to Scala collections before calling map:
import scala.collection.JavaConverters._
Files.walk(dir).iterator().asScala.map(_.toFile).foreach(println)

Scala Type Inference Not Working for GADTs in IntelliJ

Following code does not appear as compiling in IntelliJ. It is complaining that the type returned from the eval should be A where I would expect it to infer during usage. The code compiles fine using sbt but does not compile on IntelliJ with both Scala version 2 and 3 (it runs fine but shows error message in code). Is there a special configuration (e.g. sbt params, jvm args etc) that is required for code below to appear as compiled on IntelliJ?
object Solution1 {
trait Expr[A]
case class B(bool: Boolean) extends Expr[Boolean]
case class I(i: Int) extends Expr[Int]
def eval[A](expr: Expr[A]): A = expr match {
case B(b) => b
case I(i) => i
}
}
Generalized algebraic data types (GADTs) are known to be extremely difficult to implement correctly in Scala. AFAIK both the scalac and dotty compilers currently have type soundness holes, particularly using covariant GADTs.
Your eval should return a value of type T, but since i has type Int and b has type Boolean, it seems the compiler is able to see that because I is a subtype of Expr[Int], T must be equal to Int and then T must be equal to Boolean in the same way.
I am surprised this type checks. It's odd because one would expect T to keep it's meaning. It seems Scala 2's GATDs implementation is still faulty.
I'm not surprised Intellij's Scala Plugin flags it red. You can report this, but I'm not sure whether they can do anything about it as it seems Scala is flawed here for the time being. It needs special treatment for them.

Where does Scala's 'NotInferedT' come from?

In Scala, we can get a compile error with a message containing 'NotInferedT'. For example :
expected: (NotInferedT, NotInferedT) => Boolean, actual: (Nothing, Nothing)
(as seen here ).
This messge is coming from the Scala compiler, and it appears to mean that Scala cannot infer a type. But is 'NotInferedT' itself a type ? And is it described in the Scala documentation somewhere ?
I can't find 'NotInferedT' in the Scala API docs .
It's the way the Scala plugin (which is basically a Scala compiler) for IntelliJ IDEA names an undefined type it can't resolve:
case UndefinedType(tpt, _) => "NotInfered" + tpt.name

IntelliJ IDEA: default parameter values in Scala

In Scala REPL I can use Seq[String]() as a default value for a parameter of type Seq[T].
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_101).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def d[T](foo: Seq[T] = Seq[String]()) = 12
d: [T](foo: Seq[T])Int
scala> d()
res0: Int = 12
Trying the same in IDEA, it complains “Seq[String] doesn't conform to expected type Seq[T]”. Why?
IntelliJ IDEA 2016.2.4
Scala Plugin 2016.2.1
Scala 2.11.7
Note 1: Sorry, I know that my example function does not make much sense. However, my real (and useful) function is unnecessarily complex to post it here.
Note 2: At first, instead of type T my type name in the example was Any which was not a good idea (because it shadowed scala.Any) and caused some confusion. Thus I fixed that.
When you say def d[Any], the Any here is a generic place holder. It does not point to class Any in scala. It basically shadows the Any class defined globally in scala. So, when you assign Seq[String] to Seq[Any], the compiler does not know any relation between String and Any. Note that Any could be replaced with any character / word as generic place holder. The result would be the same.
Now coming, to why this works in REPL, I am not exactly sure why REPL accepts if Seq[String] when given as a default value, but I was able to reproduce the error in repl when I do the same operation inside the method body.
The following code in REPL throws error:
def d[Any](foo: Seq[Any]) = {
val a: Seq[Any] = Seq[String]()
}
<console>:12: error: type mismatch;
found : Seq[String]
required: Seq[Any]
val a: Seq[Any] = Seq[String]()
^
I am not sure why REPL was not able to catch the error while given as a default argument.
One alternative theory is, in general when you use generics, the value of the type will be determined based on the caller. For example,
def d[A](a:A) = {}
d(1) // Type of A is Int
d("a") // Type of A is String
So, when you give default value, it assigns the value of String to Any. hence the compilation success.Intellij's Type Checker works based on the first theory and shows an error. But strangely as someone pointed out earlier, the compilation succeeds.

[Akka]: Passing generic type function without type loss

I have a actor message of the following type:
case class RetrieveEntities[A](func:(Vector[A]) => Vector[A])
I then would like to handle the message in the following way:
def receive = {
case RetrieveEntities(parameters, func) =>
context.become(retrieveEntities(func))
def retrieveEntities(func:(Vector[T]) => Vector[T])(implicit mf: Manifest[T]){
case _ => ...
}
And I instantiate the actor in the following way:
TestActorRef(new RetrieveEntitiesService[Picture])
The problem is I receive the following compiler error:
type mismatch;
[error] found : Vector[Any] => Vector[Any]
[error] required: Vector[T] => Vector[T]
[error] context.become(retrieveEntities(func))
Which I suppose means I lost the type information but I am unsure why and how to prevent it.
Your example code is a bit to short to give you a solution, but from what you show it seems like what you are trying to do is not possible.
This is why
In Scala (and Java) the type parameters are erased, which means they disappear after compilation, so during runtime they are no longer available. This means that your pattern match on RetrieveEntities(parameters, func) is really a match where A can be anything. You then go on and call a method that is typed with T and there is no way for the compiler to know what you mean with that.
Manifest (which is deprecated), TypeTag and ClassTag are a mechanism that tells the compiler to create an object that provides type information for those after compilation but you have to "save" that information.
To be able to know what A you typed your RetrieveEntitiesService with you would need to take an implicit ClassTag to the constructor to base any logic on it (since when calling the constructor is the time that you know what A is):
import scala.reflect.ClassTag
case class RetrieveEntities[A](func:(Vector[A]) => Vector[A])(implicit val tag: ClassTag[A])
You could then call runtimeClass on the tag to get the type of A:
scala> val retrieve = RetrieveEntities[String](identity)
scala> retrieve.tag.runtimeClass
res2: Class[_] = class java.lang.String
Note that this still would not let you type a method call with since we are now in runtime, but it would let you use that instance of Class to compare with the runtimeClass of E of the actor and then do a safe cast to RetrieveEntities[E] if you like. (and also regular runtime conditional flows, reflection etc.).
Two important notes before you start doing that
I would not advice you to go down that path until you are more confident with the type system and really really know that there is no other reasonable design that solves your problem. Again I can not help you towards such a solution with the sparse example code given. (Maybe your actor does not really need to know about the type of A for example, or there is a limited set of E:s that you might match on with concrete types)
As an additional warning, type and class tags are not thread safe in Scala 2.10, and might not be safe in 2.11 either, so mixing them with actors might be a bad idea. (http://docs.scala-lang.org/overviews/reflection/thread-safety.html)
johanandren's answer was certainly helpful, but at the end I found a way that it could compile and it is working for now.
I needed to give the compiler a more precise type annotation to make it work:
case RetrieveEntities(parameters, func:(Vector[T]) => Vector[T])
I still will continue to use Manifest instead of the new Reflection API (TypeTag and ClassTag) mainly because the library I am using (json4s) uses internally also the Manifest implementation, and I assume it will lead to less problems this way.