What is the consequence of ignoring scala's advanced feature warning? - scala

I'm reading this tutorial about implicit conversion.
I entered this code in REPL with -feature switch:
object Rational {
implicit def intToRational(x: Int): Rational = new Rational(x)
}
And I got this warning:
<console>:9: warning: implicit conversion method intToRational should be enabled
by making the implicit value scala.language.implicitConversions visible.
This can be achieved by adding the import clause 'import scala.language.implicitConversions'
or by setting the compiler option -language:implicitConversions.
See the Scala docs for value scala.language.implicitConversions for a discussion
why the feature should be explicitly enabled.
implicit def intToRational(x: Int): Rational = new Rational(x)
But the implicit conversion works fine when I run this code:
scala> 12 * new Rational(1, 3)
res5: Rational = 4/1
So is there bad consequence if I don't follow the warning suggestion? (i.e. adding import clause or setting compiler option)

Possibly in some future version the code won't compile without adding the import clause. Or if you want to use -Xfatal-warnings.
For other feature warnings (reflective calls in particular) you may actually want to eliminate them; this doesn't really apply to this specific warning. Read the docs, as the warning suggests.

Related

In scala 2 or 3, is it possible to debug implicit resolution process in runtime?

In scala language, implicit resolution is often done in compile-time and sometimes throws obfuscating error information, one famous example of such error is when shapeless Generic throws error information like:
error: could not find implicit value for parameter encoder: CsvEncoder[Foo]
(see https://books.underscore.io/shapeless-guide/shapeless-guide.html for detail)
A solution to this problem is to run implicit resolution algorithm (should be a graph query algorithm internally) in runtime, this has at least 2 benefits:
debugging tools can be used to reproduce the resolution process step-by-step, so even error information & documentations are incomplete it would be easy to spot the error.
in many cases type information can be impossible to be determined in compile-time (e.g. type depending on the control flow). If implicit conversion cannot be delayed to runtime phase, many benefit of defining implicit conversion will be nullified.
So my question is, does this feature exist in Scala 2.x or Dotty? Or is it on the roadmap?
Thanks a lot for your opinion.
You can debug implicits at compile time:
switch on compiler flag -Xlog-implicits
try to resolve implicits manually (maybe specifying type parameters as well) and see compile errors
implicitly[...](...manually...)
use scala.reflect
println(reify { implicitly[...] }.tree)
(or switch on compiler flag -Xprint:typer) in order to see how implicits are resolved
use IDE functionality to show implicits
using macros with compiler internals you can debug implicit resolution
Is there a type-class that checks for existence of at least one implicit of a type?
create an ambiguous low priority implicit
Using the "Prolog in Scala" to find available type class instances
Finding the second matching implicit
shapeless/package.scala#L119-L168 (def cachedImplicitImpl[T](implicit tTag: WeakTypeTag[T]): Tree = ...)
If you're developing a type class don't forget to use annotations #implicitNotFound and #implicitAmbiguous.
You can always postpone compilation of your program till runtime. So instead of program
object App {
def main(args: Array[String]): Unit = {
println("test") // test
}
}
you can have
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val toolbox = currentMirror.mkToolBox()
toolbox.eval(q"""
object App {
def main(args: Array[String]): Unit = {
println("test")
}
}
App.main(Array())
""") // test
And instead of
implicitly[Numeric[Int]]
you can have
toolbox.compile(q"""
implicitly[Numeric[Int]]
""")
or
toolbox.inferImplicitValue(
toolbox.typecheck(tq"Numeric[Int]", mode = toolbox.TYPEmode).tpe,
silent = false
)
But it's too optimistic to think that postponing program compilation till runtime you'll be able to debug implicits easier at runtime rather than at compile time. Actually postponing program compilation till runtime you add one level of indirection more i.e. make things harder to debug.

REPL warning on using structural types

Why REPL gives warning on using structural types? Are structural types unsafe to use?
scala> def test(st: { def close():Unit})
| = st.close()
<console>:12: warning: reflective access of structural type member method close should be enabled
by making the implicit value scala.language.reflectiveCalls visible.
This can be achieved by adding the import clause 'import scala.language.reflectiveCalls'
or by setting the compiler option -language:reflectiveCalls.
See the Scaladoc for value scala.language.reflectiveCalls for a discussion
why the feature should be explicitly enabled.
= st.close()
^
test: (st: AnyRef{def close(): Unit})Unit
The warning suggests viewing the Scaladoc page, which says
Why control it? Reflection is not available on all platforms. Popular
tools such as ProGuard have problems dealing with it. Even where
reflection is available, reflective dispatch can lead to surprising
performance degradations.
Source
To make the warning go away, simply add import scala.language.reflectiveCalls to the top of your file to indicate that, yes, you do in fact intend to use this language feature.
I would like to put another point of view than Silvio Mayolo's answer.
Fundamentally the important thing here is that Scala is compiled into a JVM rather than some Scala-specific target platform. This means that many features that exist in Scala are not supported out of the box by the target platform (JVM) and they have to be somehow simulated by the compiler. One of such features is structural types and it is implemented using reflection. And using reflection introduces a bunch of potential issues that are mentioned in Silvio's answer. Thus compiler developers want to make sure that you understand possible drawbacks and still want to use this feature by enforcing either explicit import, compiler configuration or warning.
As for alternatives in your case you may use java.lang.AutoCloseable instead of your structural type and it will probably cover most of your cases.
Another alternative is to use implicit parameter and type class idea:
trait CloseableTC[A] {
def close(closeable: A): Unit
}
object CloseableTC {
implicit val javaCloseable: CloseableTC[java.lang.AutoCloseable] = new CloseableTC[java.lang.AutoCloseable] {
override def close(closeable: AutoCloseable): Unit = closeable.close()
}
// add here more implicits for other classes with .close()
}
def testTC[A](a: A)(implicit closeableTC: CloseableTC[A]) = closeableTC.close(a)
import CloseableTC._

Excluding type evidence parameters from analysis in Scala when using -Ywarn-unused

Compiling a program that contains a type evidence parameter in Scala (such as T <:< U) can cause a warning when -Ywarn-unused is passed to the compiler. Especially in the case when the type evidence parameter is used to verify a constraint encoded using phantom types, this warning is likely to occur.
As an example, compiling the file here:
https://github.com/hseeberger/demo-phantom-types/blob/master/src/main/scala/de/heikoseeberger/demophantomtypes/Hacker.scala returns the following:
# scalac -Ywarn-unused Hacker.scala
Hacker.scala:42: warning: parameter value ev in method hackOn is never used
def hackOn(implicit ev: IsCaffeinated[S]): Hacker[State.Decaffeinated] = {
^
Hacker.scala:47: warning: parameter value ev in method drinkCoffee is never used
def drinkCoffee(implicit ev: IsDecaffeinated[S]): Hacker[State.Caffeinated] = {
^
two warnings found
It's clear to me that the parameter ev is not actually necessary at runtime, but the parameter is useful at compile time. Is there any way to instruct the compiler to ignore this case, while still raising the warning for unused function parameters in other contexts?
For example, I think instructing the compiler to ignore implicit parameters of class <:< or =:= would solve this issue, but I'm not sure how that could be accomplished.
I often find myself adding this because of either -Ywarn-unused or -Ywarn-value-discard:
package myproject
package object syntax {
implicit class IdOps[A](a: A) {
def unused: Unit = ()
}
}
Lets you do ev.unused in the code to explicitly "specify" that the value is not going to be used or is only there for side effects. You're not using class field in the definition, but that's okay for -Ywarn-unused.
Your other option is to use silencer plugin to suppress warnings for these few methods.
Many years later, it's worth to mention there is am #unused annotation available (since when, I am not sure):
import scala.annotation.unused
def drinkCoffee(implicit #unused ev: IsDecaffeinated[S]): Hacker[State.Caffeinated]
Consequently, you can not use a context-bounds

What does "reflective access of structural type member method should be enabled..." warning mean in Scala?

After switching to Scala 2.10 I get tons of warnings:
reflective access of structural type member method ... should be enabled by making the implicit value language.reflectiveCalls visible
What does it mean?
The warning actually tells where to look in the documentation for an explanation:
Test.scala:9: warning: reflective access of structural type member method y should be enabled
by making the implicit value language.reflectiveCalls visible.
This can be achieved by adding the import clause 'import scala.language.reflectiveCalls'
or by setting the compiler option -language:reflectiveCalls.
See the Scala docs for value scala.language.reflectiveCalls for a discussion
why the feature should be explicitly enabled.
Referenced Scaladoc entry (be sure to click the |> arrow to the left to expand the documentation entry).
From Scala Docs:
Why control it? Reflection is not available on all platforms. Popular tools such as ProGuard have problems dealing with it. Even where reflection is available, reflective dispatch can lead to surprising performance degradations.
Think about this code that uses an anonymous subclass:
class Student(val id:Int)
val specialStudent = new Student(0) {
val greeting = "I am a special student with id " + id // Warning: id can be obfuscated
}
Link to Scala Docs
I ran into this warning with a function I was using to divide an Option[Double or Long] by 100:
def safeDivideBy100[T <: AnyVal { def toDouble: Double }](number: Option[T]): Option[Double] =
number match {
case None => None
case Some(x) => Some(x.toDouble / 100)
}
Fixing it simply required adding to the top of the file:
import scala.language.reflectiveCalls

Strange behavior with implicits

I'm using the Scalacheck library to test my application. In that library there's a Gen object that defines implicit conversions of any object to a generator of objects of that class.
E.g., importing Gen._ lets you call methods such as sample on any object, through its implicit conversion to Gen:
scala> import org.scalacheck.Gen._
import org.scalacheck.Gen._
scala> "foo" sample
res1: Option[java.lang.String] = Some(foo)
In this example, the implicit Gen.value() is applied to "foo", yielding a generator that always returns Some(foo).
But this doesn't work:
scala> import org.scalacheck.Gen.value
import org.scalacheck.Gen.value
scala> "foo" sample
<console>:5: error: value sample is not a member of java.lang.String
"foo" sample
^
Why not?
Update
I'm using Scala 2.7.7final and ScalaCheck 2.7.7-1.6.
Update
Just switched to Scala 2.8.0.final with ScalaCheck 2.8.0-1.7. The problem did indeed go away.
I just tried this with Scala 2.8.0.final and ScalaCheck 1.7 built for the same. Both imports worked, meaning the second line produced the desired result for both imports:
scala> "foo" sample
res1: Option[java.lang.String] = Some(foo)
What version of Scala and ScalaCheck did you use?
Simple: You did not import the implicit conversion (whatever its name is), you only imported something called value from object org.scalacheck.Gen.
Correction / clarification:
Gen.value (that's object Gen, not trait Gen[+T]) is the implicit used to wrap arbitrary values in an instance of (an anonymous class implementing) trait Gen[T] (where T is a function from Gen.Params to the argument to which Gen.value is applied). Gen.sample is a method of trait Gen[T] that invokes its (the concrete Gen subclass) apply method to get the synthesized value.
Sadly, having looked closer, I have to admit I don't understand why the code doesn't work when the rest of the members of object Gen are not imported.