Why does usage of Option.get gives a compile error - scala

I want to filter out options which are not defined in a sequence and create sequence without Options(with the actual value). I am trying to compile the following code in scala :
val idLibId = idOptionalLibId.filter(idOptionalLibId => idOptionalLibId._2.isDefined)
.map(idLibId => idLibId._1 -> idLibId._2.get)
idOptionalLibId is Seq of tuples.
But it gives me the follownig error:
[error] MandatoryApprovalOverride.scala:27:55: Use of Option.get
[error] .map(idLibId => (idLibId._1 -> idLibId._2.get))
[error]
Anyone had similar problem?

Calling .get on an Option is dangerous because it will throw if the value is None. You know that you've filtered all the None values out but the compiler doesn't.
Wouldn't this be a better way to do it?
val idLibId = idOptionalLibId.collect{case (k,Some(v)) => k -> v}

The only reason this would be an error is due to settings of your particular project, e.g. a combination of WartRemover to warn on Option.get and -Xfatal-warnings to turn all warnings into errors. You can see https://www.wartremover.org/doc/warts.html for motivation:
scala.Option has a get method which will throw if the value is None. The program should be refactored to use scala.Option#fold to explicitly handle both the Some and None cases.
and likely other cases where you'll run into similar warnings/errors (depending on WartRemover configuration in your project).
Though in this case the fix proposed by #jwvh is better than fold or getOrElse.

Related

How do you debug typelevel code?

Most of the time, all you get is an implicit not found error. You don't know where in the chain of implicit construction it failed. Apparently you can't use runtime debug or print statement. So how do you debug type-level program other than staring at your code really hard?
I wish I had a better answer, but here it goes: Start passing the parameters explicitly, one at a time until it gives you a more useful error. (adding-prinlns-equivalent for implicits params)
You can use ??? for undefined code parts (because it have bottom type Nothing) and _ for unknown types. Also see -Ytyper-debug compiler option (more options here: https://docs.scala-lang.org/overviews/compiler-options/index.html). According to problem with implicit parameters and wrappers, "Idea" has nice feature "Show Implicit Hints" and "Implicit Arguments" (Main menu > Help > Find Action... and type e.g. implicit). Also, you can use Null bottom type instance null for AnyRef like null: YourTypeHere.

How to actually fix the postfix Ops issue

I have found several questions on the subject of the Scala compiler warning:
postfix operator xxx should be enabled by making the implicit value
scala.language.postfixOps visible. This can be achieved by adding the
import clause 'import scala.language.postfixOps' or by setting the
compiler option -language:postfixOps. See the Scala docs for value
scala.language.postfixOps for a discussion why the feature should be
explicitly enabled.
Here's an example of where this warning shows up:
val m1 = List(1->"a",2->"b") toMap
None really answered what I wanted to know when I first came across this problem: how do I fix this problem without involving the import or the compiler option. My first thought was this: if it doesn't like postfix ops, then make the method/op call explicit by replacing the space with a dot. For example:
val m1 = List(1->"a",2->"b").toMap
Unfortunately, when I first tried that fix, the code that I happened to be working on at the time looked something like this:
val m2 = List(1->"a",2->"b") map {case (k,v) => (k.toString,v)} toMap
When I added the dot, this resulted in yet another obscure compiler error:
val m2 = List(1->"a",2->"b") map {case (k,v) => (k.toString,v)}.toMap
missing parameter type for expanded function The argument types of an
anonymous function must be fully known. (SLS 8.5) Expected type was: ?
which related to the k and v identifiers.
Back then, I just gave up and added the import statement and all was well. However, a student recently asked me about this issue and I thought I'd better go back and investigate. See my answer to the problem which, now that I think about it, is rather obvious. Yet I hope to save some others the time that it takes to wade through all of the other discussions of this subject.
What I usually do in this situation, I'll add a dot to the first call:
val m2 = List(1->"a",2->"b").map {case (k,v) => (k.toString,v)}.toMap
Personally, I prefer this to having extra parenthesis.
The answer has to do with the associativity of the operators ("." binds more tightly than map). The answer of course is to override the binding with parentheses:
val m2 = (List(1->"a",2->"b") map {case (k,v) => (k.toString,v)}).toMap

dsl for capturing field name

I'm working on a mapper and wanted a typesafe way to capture class fieldnames for mapping and went with a syntax I'd used in C#:
case class Person(name: String, age: Int)
new Mapping[Person]() {
field(_.age).name("person_age").colType[java.lang.Integer]
field(_.name).name("person_name")
}
where def field(m: T => Unit): FieldMap
This triggers the following warnings:
Warning:(97, 13) a pure expression does nothing in statement position; you may be omitting necessary parentheses
field(_.age).name("person_age").colType[java.lang.Integer]
^
Warning:(98, 13) a pure expression does nothing in statement position; you may be omitting necessary parentheses
field(_.name).name("person_name")
^
So clearly that's not a desirable syntax. Any way I can tweak the signature of field to avoid the warning or is there a more idiomatic scala way of mapping fields in a typesafe manner?
Note: #sjrd's answer indeed gets rid of the warning, but the attempted feature doesn't seem feasible with scala reflection after all. My end goal is a Mapper that allows the specifying of T members in a compile time checked mannner, rather than strings, so it's less vulnerable to typo's and refactoring issues.
The field method takes a T => Unit function as parameter. Hence, the lambda _.age, which is equivalent to x => x.age, is typechecked as returning Unit. The compiler warns that you are using a pure expression (x.age) in statement position (expected type Unit), which basically means that the expression is useless, and might as well be removed.
There is a very simple symptomatic solution to your problem: replace m: T => Unit by m: T => Any. Now your expression x.age is not in statement position anymore, and the compiler is happy.
But your code suggests that there is something wrong a little bit deeper, since you obviously don't use the result of m anywhere. Why is m for anyway?

[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.

Avoiding type erasure warnings

I have some code where I have a collection of functions. Each function might have 1 or 2 arguments. When iterating through these functions I check whether the element is of type Function1 or Function2. The problem is that I start getting type erasure warnings because I have to define the parameter datatypes in order for it to compile (ex. Function2[String,Int] -- see example warning below+).
I understand that Java strips the parameter type information away when it gets compiled so it can't pattern match the Function2 that I am defining. The thing is, I only want to test if the function is of type Function1 or Function2, and from there I know what data types I need to pass to the function. I tried defining them as ex. Function2[Any,Any] and Function2[Object,Object], but neither of these suppressed the warnings. Is there any way to pattern match against functions of different parameter counts without asking it to also check the parameter types?
[warn] /home/ubuntu/aa-2-0/src/main/scala/hw.scala:818: non-variable type argument Any in type Any => Any is unchecked since it is eliminated by erasure
[warn] else if(col_data.isInstanceOf[Function1[Any,Any]]) mapped_data+= col -> col_data.asInstanceOf[Function1[Any,String]].apply(page)
[warn] ^
[warn] /home/ubuntu/aa-2-0/src/main/scala/hw.scala:819: non-variable type argument Any in type (Any, Any) => Any is unchecked since it is eliminated by erasure
[warn] else if(col_data.isInstanceOf[Function2[Any,Any,Any]]) mapped_data+= col -> col_data.asInstanceOf[Function2[Any,Any,String]].apply(result_row,page)
I know there is reflection and tagtypes and all that, but those seem like ugly and overly elaborate hacks to solve my rather trivial problem. Instead, I was planning to resort to encapsulating these functions in FunctionOne,FunctionTwo case classes then just test for those, but wanted to first see if there was a more elegant solution to be learned.
I wouldn't make assorted lists of different function types, which gives you this problem. But if you must, you can use wildcards:
if(col_data.isInstanceOf[Function1[_,_]])
(You can also use the sugared notation _ => _, (_,_) => _ etc.)