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._
Related
Taken from "Scala with cats" (page 18):
Implicit Conversions
When you create a type class instance constructor using an implicit def, be sure to mark the parameters to the method as implicit parameters. Without this keyword, the compiler won’t be able to fill in the parameters during implicit resolution. implicit methods with non‐implicit parameters form a different Scala pattern called an implicit conversion. This is also different from the previous section on Interface Syntax, because in that case the JsonWriter is an implicit class with extension methods. Implicit conversion is an older programming pattern that is frowned upon in modern Scala code. Fortunately, the compiler will warn you when you do this. You have to manually enable implicit conversions by importing scala.language.implicitConversions in your file
Can anyone please sum up well why implicit conversion are deprecated? What were there limit or issues? Why the approach with implicit parameters is better?
Note I know how to use the modern approach well, including chaining implicit and all. I am just curious as to what was the issue and why it was deprecated.
Martin Odersky, the inventor of Scala, has indicated that implicits (and implicit conversions) are being deprecated in scala 3.1 and will eventually be removed from the language altogether.
the implicit functionality will be replaced with Extension Methods and Givens. Extension Methods and Givens provide a more tighter functional solution that doesn't introduce the unsuspecting and hidden side effects that implicits cause. Odersky now views implicits as a “recipe for disaster" and are "too implicit" which was his motivation to replace their functionality in 3.x.
https://www.slideshare.net/Lightbend/scala-3-is-coming-martin-odersky-shares-what-to-know
https://hub.packtpub.com/is-scala-3-0-a-new-language-all-together-martin-odersky-its-designer-says-yes-and-no/
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.
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
Or is this even relevant?
What I have in mind is using the ClassTag or TypeTag annotations, like so:
scala>
import scala.reflect.runtime.universe.TypeTag
def f[T : TypeTag](ls : List[T]) : String = {
???
}
results in :
f: [T](ls: List[T])(implicit evidence$1: reflect.runtime.universe.TypeTag[T])String
As you can see, the TypeTag is seen by the compiler which adds an implicit argument. Is there an equivalent in scala.meta? How will this work, and will there be any changes in the way erasure is handled?
At the moment scala.meta does not provide runtime introspection, however, that's planned for future releases. APIs would be similar to scala.reflect (but in terms of scala.meta, e.g. different Abstract Syntax Trees, no exposed compiler internals, etc), and I really hope that end user wont see much difference.
So, functionality of ClassTag/TypeTag is not likely to disappear. Most probably, scala.meta will use a bridge (paradise) to get access to scalac internals (and that involves scala.reflect).
Also note that scala.reflect will be supported in scala 2.x branch, but not in dotty.
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