In Scala 2.13, why is it possible to summon unqualified TypeTag for abstract type? - scala

Considering the following code:
import scala.reflect.api.Universe
object UnqualifiedTypeTag {
val RuntimeUniverse = scala.reflect.runtime.universe
trait HasUniverse {
val universe: Universe with Singleton
def uType: RuntimeUniverse.TypeTag[universe.type] = implicitly
}
object HasRuntime extends HasUniverse {
override val universe: RuntimeUniverse.type = RuntimeUniverse
}
def main(args: Array[String]): Unit = {
println(HasRuntime.uType)
}
}
Ideally, this part of the program should yield TypeTag[HasRuntime.universe.type], or at least fail its compilation, due to implicitly only able to see universe.type, which is not known at call site. (in contrast, WeakTypeTag[universe.type] should totally work)
Surprisingly, the above program yields TypeTag[HasUniverse.this.universe.type]. This apparently breaks many contracts, namely:
TypeTag cannot be initialised from abstract types, unlike WeakTypeTag
TypeTag can always be erased to a Class
What's the purpose of this design, and what contract does TypeTag provide? In addition, is this the reason why ClassTag was supposed to be superseded after Scala 2.11, but instead was kept as-is until now?

Related

In Scala 3, is it possible to use declared type of an object in runtime?

In Scala 2, most generic type information of an object is erased at runtime. At this moment, all 3 binary execution environments (JVM, javascript, and LLVM) abide this behaviour, they only differs in minor details in metadata formats.
In a rare case if it incurs critical data loss, or if it triggers a rare binary error. A mechanism should be used to preserve declared type information in an adjoint data structure. The following code gave a short example of such data structure in Scala 2:
import scala.reflect.runtime.universe
import scala.collection.concurrent.TrieMap
import scala.language.implicitConversions
case class Unerase[T](self: T)(
implicit
ev: universe.TypeTag[T]
) {
import Unerase._
cache += {
val inMemoryId = System.identityHashCode(this)
inMemoryId -> ev
}
}
object Unerase {
lazy val cache = TrieMap.empty[Int, universe.TypeTag[_]]
def get[T](v: T): Option[universe.TypeTag[T]] = {
val inMemoryId = System.identityHashCode(v)
cache.get(inMemoryId).map { tt =>
tt.asInstanceOf[universe.TypeTag[T]]
}
}
implicit def unbox[T](v: Unerase[T]): T = v.self
implicit def box[T](v: T)(
implicit
ev: universe.TypeTag[T]
): Unerase[T] = Unerase(v)
}
Any variable declared as type Unerase[T] instead of T will be guaranteed to have its full declared type visible at runtime. Unfortunately, this example no longer works in Scala 3:
implicitly[TypeTag[Int]] // works in Scala 2
summon[Type[Int]] // doesn't work in Scala 3: No given instance of type quoted.Quotes was found for parameter x$1 ...
Is there a mechanism that I can use to implement the same mechanism to fully mitigate type erasure?

Scala 3 Macro - Retain a generic type in runtime

I'm looking for an option to retain a generic type in runtime in Scala3. In Scala2 there was a TypeTag for this, however, now it is removed and the suggested option is to use macros (https://contributors.scala-lang.org/t/scala-3-and-reflection/3627).
The documentation, however, is somewhat cryptic...
This is what I'm trying to do:
Here's a macro implementation:
object TestMacroImpl {
def getClassImpl[T](using Quotes)(using t: Type[T]): Expr[Class[T]] = '{
classOf[${t}]
}
}
Here's a macro:
import macros.TestMacro.getClassMacro
class TypedBox[T] {
val staticClass: Class[T] = TypedBox.getStaticClass[T]
}
object TypedBox {
inline def getStaticClass[T] = ${ getClassMacro[T] }
}
Test:
object Test {
def main(args: Array[String]): Unit = {
val stringBox = TypedBox[String]()
println(stringBox.staticClass)
}
}
I would envision this to be resolved as val staticClass = classOf[String]
But this does not compile, I'm getting:
/workspace/macros-test/src/main/scala/macros/TestMacro.scala:7:13
t.Underlying is not a class type
classOf[${t}]
What am I missing?
Not really sure why but I don't think you can reliably get an Expr[Class[T]] out of macros (from what I understood, it could be that the Class does not yet exist at the time of macro execution).
Plus, a Class[T] does not retain the parameterized types: classOf[Map [String, String]] = classOf[Map[Int, Int]] for instance.
If you don't care about them, I'd use a ClassTag instead of TypeTag which is still available in Scala 3. And no need for macros.
By the way, in macros, you can write something like the following to get a Expr[ClassTag[T]]:
private def getClassTag[T](using Type[T], Quotes): Expr[ClassTag[T]] = {
import quotes.reflect._
Expr.summon[ClassTag[T]] match {
case Some(ct) =>
ct
case None =>
report.error(
s"Unable to find a ClassTag for type ${Type.show[T]}",
Position.ofMacroExpansion
)
throw new Exception("Error when applying macro")
}
}
Finally, you might find some useful things at https://github.com/gaeljw/typetrees/blob/main/src/main/scala/io/github/gaeljw/typetrees/TypeTreeTagMacros.scala#L8 (disclaimer: I wrote it for personal projects).

Creating `**` power operator for Scala?

I quite like the ** syntax for pow, available in many languages (such as Python).
Is it possible to introduce this into Scala, without modifying the Scala 'base' code?
My attempt at an Int only one:
import scala.math.pow
implicit class PowerInt(i: Int) {
def `**`(n: Int, b: Int): Int = pow(n, b).intValue
}
(see it failing on IDEone)
this works for me: (problem#1 pow is defined on doubles, problem#2 extending anyval)
(also there is no point in having those backticks in the methodname?)
import scala.math.pow
object RichIntt {
implicit class PowerInt(val i:Double) extends AnyVal {
def ** (exp:Double):Double = pow(i,exp)
}
def main(args:Array[String])
{
println(5**6)
}
}
This answer is 2 years late, still for the benefit of others I'd like to point out that the accepted answer unnecessarily extends from AnyVal.
There is just a minor bug that needs to be fixed in the original answer. The def ** method needs only one parameter, i.e. the exponent as the base is already passed in the constructor and not two as in the original code. Fixing that and removing the backticks results in:
import scala.math.pow
implicit class PowerInt(i: Int) {
def ** (b: Int): Int = pow(i, b).intValue
}
Which works as expected as seen here.
Scala compiler will cast an Int to a PowerInt only if the method that is called on it is undefined. That's why you don't need to extend from AnyVal.
Behind the scenes, Scala looks for an implicit class whose constructor argument type is the same as the type of the object that is cast. Since the object can have only one type, implicit classes cannot have more than one argument in their constructor. Moreover, if you define two implicit classes with the same constructor type, make sure their functions have unique signatures otherwise Scala wouldn't know which class to cast to and will complain about the ambiguity.
There is a way to make the solution a little bit more generic using Numeric typeclass:
implicit class PowerOp[T: Numeric](value: T) {
import Numeric.Implicits._
import scala.math.pow
def **(power: T): Double = pow(value.toDouble(), power.toDouble())
}
This is my solution using recursion (so I don't need import scala.Math.pow):
object RichInt {
implicit class PowerInt(val base:Double) {
def ** (pow:Double):Double = if (pow==0) 1 else base*(base**(pow-1))
}
def main(args:Array[String]){
println(2.0**3.0) //8.0
println(2.0**0.0) //1.0
}
}

Abstract reflection API in Scala 2.10

Scala 2.10 comes with a great reflection API. There are two entry points to it, however: runtime universe and macro context universe.
When using runtime reflection, you should import scala.reflect.runtime.universe. When using reflection inside a macro implementation, you should import universe from the context.
Is it possible to write some code that works in both environments? How should one obtain the universe?
Consider this example:
class MyReflection(val u: scala.reflect.api.Universe) {
import u._
def foo[T: TypeTag] = implicitly[TypeTag[T]].tpe.members // returns MyReflection.u.MemberScope
}
val x = new MyReflection(scala.reflect.runtime.universe)
val members: scala.reflect.runtime.universe.MemberScope = x.foo[String] // BANG! Compiler error
This won't compile because of type mismatch. Same time, it is obvious that both scala.reflect.runtime.universe.MemberScope and MyReflection.u.MemberScope in this example share the same API. Is there a way to abstract over different universes?
Or am I possibly doing something philosophically wrong with trying to export reflection artifacts (MemberScope in this example)?
You can just accept the universe as a parameter:
class MyReflection(val u: scala.reflect.api.Universe) {
import u._
def foo[T : TypeTag] = implicitly[TypeTag[T]].tpe.members
}
val x = new MyReflection(scala.reflect.runtime.universe)
Note that you'll have to refer to the universe via your instance of MyReflection to get the path-dependent types right.
val members: x.u.MemberScope = x.foo[String]
Have a look at this question for more examples and options.

How do you define implicit conversion in modern way?

Stupid question, but none of the examples works for me; classic article "Pimp my Library" is buggy and even the simplest code has problems.
Btw. I assume you have to put conversion method in the object (a lot of snippets omit that part). According to PiS book it seems hanging implicit def is OK, but this gives me error as well.
object Minutes
{
implicit def toMinutes(x : Int) = new Minutes(x)
}
class Minutes(private val x : Int)
{
def minutes = x.toString+"m"
}
object MainApp {
def main(args : Array[String])
{
println(5.minutes)
...
The error -- "value minutes is not a member of Int".
Question
What am I missing? Scala 2.9.1.
All you need you to do is bring your implicit conversion into scope where you want to use it, so the compiler can find it...
def main(args : Array[String]) {
import Minutes._
println(5.minutes)
}
The implicit conversion must be in scope, e.g.
def main(args : Array[String]) {
import Minutes._
println(5.minutes)
...
}
There are other ways, too, e.g. using package objects.
You can get the example in the Pimp my library article to work as follows:
class RichArray[T: Manifest](value: Array[T]) {
def append(other: Array[T]): Array[T] = {
val result = new Array[T](value.length + other.length)
Array.copy(value, 0, result, 0, value.length)
Array.copy(other, 0, result, value.length, other.length)
result
}
}
implicit def enrichArray[T: Manifest](xs: Array[T]) = new RichArray[T](xs)
You need a context bound for T: [T: Manifest] is short for [T](implicit m: Manifest[T]). A Manifest is a way of passing the value of T to the method at runtime, when T is known. Normally the parameterized type information is used by the compiler to ensure type safety at compile time, but is not incorporated into the bytecode because the JVM can't handle it (type erasure). Scala collections changed in version 2.8 so that for performance reasons, Arrays are now not automatically wrapped by compiler magic, hence supplying a manifest for generic operations became necessary.
The other change is the (xs) argument for new RichArray[T]. I think that one's a typo.