How do you debug typelevel code? - scala

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.

Related

Correct class names in IntelliJ debugger (scala)

I am new to scala & IntelliJ, so this might sound like a stupid question. However, I see that when debugging, IntelliJ will infer parameter types to some kind of "weird" type, in my case MapLike$MappedValues. The expected type would be Map[String, Iterable[Person]].
Why can IntelliJ not display the correct type? Right now this would be kind of important to me, because by debugging I am trying to find out the correct parameter type, because the API documentation on this part is not very clear (working with Apache Flink CEP)
Code example:
val result:DataStream[String] = patternStream.select(patterns => {
val person:Person = patterns.head._2.head
s"Person ${person.name} of age ${person.age} can drink!"
})
This is what I can see in the debugger:
According to the documentation:
"The select() method takes a selection function as argument, which is called for each matching event sequence. It receives a match in the form of Map[String, Iterable[IN]]"
Why does IntelliJ display MapLike$MappedValues and not something like Map[String,Iterable[Person]]?
The debugger is showing you the runtime class.
On the JVM, generic type parameters are "erased" at runtime, so they will not be visible in the debugger. Map is just an interface, but MapLike$MappedValues implements it as inheritor of AbstractMap.
Thus, the displayed class is compatible with the type of the value.
To find the compile time type of an expression, IntelliJ can help you:
select the expression
press the "type info" hotkey (usually shift+ctrl+p)

Prevent 0-ary functions from being called implicitly in Scala

I got nipped by a production bug where I passed an impure 0-ary function to a class that mistakenly expected a a bare result type.
def impureFunc(): Future[Any] = ???
case class MyService(impureDependency: Future[Any] /* should have been () => Future[Any] */)
Effectively, this made MyService immediately invoke impureFunc and cache the first result for the lifetime of the program, which led to a very subtle bug.
Normally, the type system prevents these sort of bugs, but because of the ability to call 0-ary functions without an argument list, the compiler accepted this program.
Obviously, this is a "feature" of Scala, designed to make code look cleaner, but this was a bad gotcha. Is there any way to make this a compiler warning or a linting error? In other words, disapprove the "Empty application" type of implicit method conversion?
From the comments here, it appears this behavior was deprecated with a warning in 2.12 and should become an error in 2.13. So it seems the answer is to use -deprecation -Xfatal-warnings after upgrading.

Prevent type mismatch error indications in Intellij IDEA?

In Intellij IDEA, I have a Scala case class expecting Longs as arguments. The arguments passed in are numbers, which intellij interprets as Ints and reports an error on it. The code compiles without errors or warnings, so he compiler (and I) don't care. It's pretty easy to fix by putting a l after the number, but that is cumbersome and does not increase readability. Is there a setting somewhere in Intellij Idea to fix this behavior?
There is an open bug (see also the linked issues):
SCL-7729 Highlight error with implicit conversion of covariant type

Force single argument in scala varargs

Given a java class with two methods (taken from mockito):
OngoingStubbing<T> thenReturn(T value);
OngoingStubbing<T> thenReturn(T value, T... values);
If I invoke from scala with
....thenReturn("something")
I get an error:
Description Resource Path Location Type
ambiguous reference to overloaded definition, both method thenReturn in trait OngoingStubbing of type (x$1: java.lang.Object, x$2: <repeated...>[java.lang.Object])org.mockito.stubbing.OngoingStubbing[java.lang.Object] and method thenReturn in trait OngoingStubbing of type (x$1: java.lang.Object)org.mockito.stubbing.OngoingStubbing[java.lang.Object] match argument types (java.lang.String)
And I cannot figure out how to fix this.
This is a known Scala-Java interoperability problem, though it's unfortunately not in the FAQ. Here's the Scala ticket describing the problem. Essentially, both methods are applicable when you give a single argument, and the Scala compiler currently doesn't have any heuristic to decide which one is "more specific". Alexey Romanov's approach to always use the varargs version is a good workaround:
thenReturn("something", Nil: _*)
There is also a question running into a similar problem with JCommander. One of the answers there gives a clever workaround using structural types. This approach will use reflection behind the scenes, so you may or may not want to go that direction. For your use case, it would look something like:
type useSingleArgVersion = { def thenReturn(value: AnyRef): OngoingStubbing }
(...).asInstanceOf[useSingleArgVersion].thenReturn("something")
Finally, there is a similar question running into a similar problem with mokito. It doesn't really provide any workarounds, but it does describe the problem in a bit more detail, if you're interested in the reason this happens.
If calling the vararg version is acceptable,
thenReturn("something", Nil: _*)
Can't think of a way to call the method without varargs right now.
These answers are all to the wrong question. The difference is subtle, but this is not the same issue as the one in the linked ticket. That one does require unreasonable gymnastics to call the non-varargs method. For this one, the following is enough.
thenReturn[String]("something")
Or, if you didn't want to do that for some reason, you don't need the type alias and the cast. You can use a structural type ascription directly.
(this: { def thenReturn[T](s: T): OngoingStubbing[T] }).thenReturn("something")
The issue here is type inference at the intersection of overloading and polymorphism - one method is more specific, but scalac doesn't figure out which. The issue in SI-2991 is genuine ambiguity due to an interaction between overloading and tuple conversion - neither is more specific.
Assuming others will find this question when having the overloaded method value thenReturn with alternatives error, I want to share my solution as well.
Instead of
when(field.getValue(isA(classOf[Record]))).thenReturn(value)
I use
doReturn(value).when(field).getValue(isA(classOf[Record]))
which resolves the disambiguity in my case.
The workaround is quite easy:
OngoingStubbing<T> thenReturn(T value);
OngoingStubbing<T> thenReturn(T value1, T valu2, T... values);
There is no "varargs must be non empty" feature.
I tried Steve's solution and got a huge compiler error including:
scala.tools.nsc.symtab.Types$TypeError: type mismatch;
found : scala.reflect.Manifest[Nothing]
required: scala.reflect.ClassManifest[B]
Note: Nothing <: B, but trait ClassManifest is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: B`. (SLS 3.2.10)
I was able to make it work with something like:
thenReturn("something", Seq.empty[Object]: _*)

How to make Scala implicits explicit in Eclipse

According to "Programming in Scala" one can pass the argument -Xprint:typer to the compiler and gets the code back as it looks after all the implicites are actually applied.
I also found that I can set compiler arguments in the project properties.
But I can't find any resulting output anywhere ...
So where do I have to look?
If you start Eclipse from a console, you should see the printed output there.
With the Scala IDE 2.1 Milestone 1 you can press Ctrl-1 to make implicits explicit
From http://scala-ide.org/download/milestone.html#scala_ide_21_milestone_1
Highlight Implicits It has never been easier to know where implicits
are applied. And, by pressing Cmd/Ctrl+1, turn an implicit conversion
into an explicit call!