scala-js "#JSGlobalScope" error when migrating to scala-js 1.1.1 - scala

I had a fallowing snippet of code in scala-js(0.6.33)
object Main2 extends App {
val js = for {
jsTest <- JSTest.js1.toOption
} yield jsTest
println(JSTest.js1)
}
import scala.scalajs.js
import scala.scalajs.js.annotation.JSGlobalScope
#js.native
#JSGlobalScope
object JSTest extends js.Object {
def js1: js.UndefOr[JS2] = js.native
}
#js.native
trait JS1 extends js.Object {
def js1: js.UndefOr[JS2] = js.native
}
#js.native
trait JS2 extends js.Object {
def js2: js.UndefOr[Int] = js.native
}
And I was migrating the project to use scala-js(1.1.1)
when I compile the same code in scala-js(1.1.1), I am getting this error: -
const value = js1;
^
ReferenceError: js1 is not defined
Can anyone help me achieve the same functionality with scala-js(1.1.1)?
configuration: -
scala -> 2.13.3, sbt -> 1.3.13, jvm -> 14

As the release notes of Scala.js 1.0.0 explain, trying to even read a member of an #JSGlobalScope object that does not actually exist in the global scope will throw a ReferenceError, whereas Scala.js 0.6.x would give undefined.
The same section of the release notes explains that, if the purpose is to check whether it is defined, it is now necessary to use an explicit test with js.typeOf. In your specific example:
object Main2 extends App {
val js = for {
jsTest <- JSTest.js1.toOption
} yield jsTest
println(JSTest.js1)
}
That would mean that you can't unconditionally access JSTest.js1 like that anymore. You first have to make sure it exists using a js.typeOf test:
object Main2 extends App {
val safeJS1 =
if (js.typeOf(JSTest.js1) == "undefined") None
else JSTest.js1.toOption
val js = for {
jsTest <- safeJS1
} yield jsTest
println(safeJS1)
}

Related

Scala 2.10 "No implicit view available" error on type parameter that asks for a view

I have reduced this example from something encountered in a much larger project; the fundamental issue seems to be that Scala 2.10 has weird or possibly broken handling of view constraints:
trait Nameish {
def name: String
}
abstract class Namer[A <% Nameish](e: Class[A]) {
def doNameThing(x: A) = println("argument is named " + x.name)
}
class SubNamer[A <% Nameish](e: Class[A]) extends Namer(e) {
}
object TestViews extends App {
import scala.language.implicitConversions
implicit def nameStr(x: String): Nameish = new StringNamer(x);
class StringNamer(x: String) extends Nameish {
def name = x
}
println(new SubNamer(classOf[String]).doNameThing("foo"))
}
When I try to compile this, in scala 2.10 I get the errors:
TestViews.scala:8: error: No implicit view available from A => Nameish.
class SubNamer[A <% Nameish](e: Class[A]) extends Namer(e) {
^
TestViews.scala:18: error: value doNameThing is not a member of SubNamer[String]
println(new SubNamer(classOf[String]).doNameThing("foo"))
^
two errors found
Note that Scala 2.11 is fine with this code.
Unfortunately, re-tooling this code to a newer scala version would make this task explode in size. I need to find a way to make the existing scala accept a class hierarchy with a type parameter that has a view constraint.
Another attempt at a way around this has uncovered a different scala-2.10-only error case:
trait Nameish {
def name: String
}
abstract class Namer[A](e: Class[A])(implicit view: A => Nameish) {
def doNameThing(x: A) = println("argument is named " + x.name)
}
class SubNamer[A](e: Class[A])(implicit view: A => Nameish) extends Namer(e)(view) {
}
object TestViews extends App {
import scala.language.implicitConversions
implicit def nameStr(x: String): Nameish = new StringNamer(x);
class StringNamer(x: String) extends Nameish {
def name = x
}
println(new SubNamer(classOf[String]).doNameThing("foo"))
}
This is just replacing the view constraints with implicit arguments.
With this code, it again compiles just fine with Scala 2.11, but on Scala 2.10:
TestViews.scala:8: error: `implicit' modifier cannot be used for top-level objects
class SubNamer[A](e: Class[A])(implicit view: A => Nameish) extends Namer(e)(view) {
^
one error found
I don't understand what's going on here: I'm not trying to declare an implicit object, I'm trying to declare that the class takes an implicit parameter. Why is it fine for the first class, but not the second one?
Adding parameter type parameter A to Namer (in the Subnamer inheritance) worked for me (Scala version 2.10.7):
class SubNamer[A <% Nameish](e: Class[A]) extends Namer[A](e)
By the way your example without modification worked for me only from the Scala version 2.11.5.
Hope this helps.

Vampiric methods, type provider macros and missing runtime.VolatileObjectRef

I am trying to write a type provider macro that uses the vampiric methods trick described in this gist; this is a minimal model of my implementation:
object DeriveFamily {
def minimal: Any = macro DeriveFamilyMacros.minimal
}
object DeriveFamilyMacros {
class body(tree: Any) extends StaticAnnotation
def bodyImpl(c: Context) = {
import c.universe._
val field = c.macroApplication.symbol
val bodyAnn = field.annotations.filter(_.tree.tpe <:< typeOf[body]).head
bodyAnn.tree.children.tail.head
}
def minimal(c: Context): c.Tree = {
import c.universe._
q"""object Foobar { val _x = "X"; #DeriveFamilyMacros.body(Foobar._x) def x: String = macro DeriveFamilyMacros.bodyImpl }; Foobar"""
}
}
This is a dumb example, the real implementation tries to use this trick to create bundles of derived typeclass instances that are accessible without reflective calls. The issue that both the real version and this one have is that they work fine if I use them in a function but they crash the compiler if I try to use them at the root of a class or object definition:
object Working {
def x = {
val foobar = DeriveFamily.minimal
println(foobar.x)
}
x // Prints "X"
}
object NotWorking {
val foobar = DeriveFamily.minimal
println(foobar.x)
/*
[trace] Stack trace suppressed: run last common/test:compileIncremental for the full output.
[error] (common/test:compileIncremental) java.lang.IllegalArgumentException: Could not find proxy for var Foobar$module: runtime.VolatileObjectRef in List(variable Foobar$module, value foobar, Object NotWorking, package <root>) (currentOwner= value <local NotWorking> )
*/
}
Any help in fixing this will be very welcome, thanks.

Scala macro annotation typecheck for implicit class fails

Macro sample code:
package macros
import scala.reflect.macros.whitebox.Context
import scala.language.experimental.macros
import scala.annotation.StaticAnnotation
class Ant extends StaticAnnotation {
def macroTransform(annottees: Any*): Unit = macro Ant.impl
}
object Ant {
def impl(c: Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
c.internal.enclosingOwner.asType.toType // this line is Ok
// ! Any commented line below causes the same compilation error
// c.internal.enclosingOwner.asType.toType.decls
// c.mirror.staticClass(c.internal.enclosingOwner.fullName + ".A".toString)
// c.typecheck(annottees.head)
q"""implicit class A(val v: Int) extends AnyVal { def ask() = println("ok") }"""
}
}
Changing whitebox.Context to macros.Context or blackbox.Context does not help.
Changing arguments withImplicitViewsDisabled=true, or withMacrosDisabled=true has no effect.
Exec sample code:
package test
import macros.Ant
object Test extends App {
val a = new A(42)
a.ask() // Output should be "ok" (not 42)
// ! removing [implicit] lets code be compiled
#Ant implicit class A(v: Int) { def ask() = println(v)}
}
So, removing line c.typecheck(annottees.head) and / or word implicit in line #Ant implicit class A(v: Int) lets code be compiled.
Otherwise compilation crashes with error:
Error:scalac:
no progress in completing object Test: <?>
while compiling: D:\Projects\_Schemee\TestMacro1\src\test\Test.scala
during phase: globalPhase=typer, enteringPhase=namer
library version: version 2.11.6
compiler version: version 2.11.6
reconstructed args: -nobootcp -classpath ...
last tree to typer: Ident(v)
tree position: <unknown>
tree tpe: Int
symbol: value v
symbol definition: v: Int (a TermSymbol)
symbol package: test
symbol owners: value v -> method A -> object Test
call site: method A in object Test in package test
<Cannot read source file>
Compiled under latest IntelliJ. With and without Sbt.
The question is: how to use typecheck in macro annotation with implicit classes? (or am i missing something?)
EDITED:
Besides that that error is caused when trying to access enclosingOwner declarations or mirror class A "manually".
Github link
Issue link
It looks like an sbt bug or interaction with compiler behavior.
The original exception:
java.lang.NullPointerException
at xsbt.Dependency$ExtractDependenciesByMemberRefTraverser$$anonfun$1.isDefinedAt(Dependency.scala:142)
That location:
val typeSymbolCollector = new CollectTypeTraverser({
case tpe if !tpe.typeSymbol.isPackage => tpe.typeSymbol
})
The traverser has a comment suggesting similar issues:
/*
* Some macros appear to contain themselves as original tree.
* We must check that we don't inspect the same tree over and over.
* See https://issues.scala-lang.org/browse/SI-8486
* https://github.com/sbt/sbt/issues/1237
* https://github.com/sbt/sbt/issues/1544
*/

Scala Reflection - Loading or finding classes based on trait

Does the scala reflection API (2.10) provide any easier means of searching the loaded classes and filtering the list to specific classes which implement a defined trait?
ie;
trait Widget {
def turn(): Int
}
class Cog extends Widget {
def turn() = {
5
}
}
class Sprocket extends Widget {
def turn() = {
10
}
}
I want to search the class library for anything that extends Widget and instantiate those classes. So I would end up with an instance of Cog and Sprocket.
I've done similar in Java iterating through the class directories, forming class names and using Class.forName to load a Class object to then check. I'm just wondering if the scala reflection API gives any easier way to search. All examples I've seen thus far have always started from a known class being instantiated, and not from searching over available classes.
This is what ServiceLoader is for.
I think the reflection API does make it easier to sort out what you need (i.e., for filtering but not for querying the class loader).
If, by your phrase, "searching the loaded classes", you really mean classes that are already loaded, see this question for getting them.
You could imagine a widgets library with an initializer that just ensures that all the widget classes it knows about are loaded. Then the client only needs to know the initializer.
The type test is the same.
val need = typeOf[Whatsit[Cog]]
for (x <- (ServiceLoader load classOf[Whatsit[_]]).asScala) {
val im = currentMirror reflect x
if (im.symbol.toType weak_<:< need)
Console println s"$x is what I need"
else
Console println s"$x is not what I need, I'm looking for a $need"
}
Where you're looking for something with type parameters:
trait Whatsit[+A <: Widget] {
def widget: A
}
class Engine extends Whatsit[Cog] {
def widget = new Cog
}
class FlyWheel extends Whatsit[Sprocket] {
def widget = new Sprocket
}
Sample:
widgets.Engine#f9da0cd is what I need
widgets.FlyWheel#4cfdbb9f is not what I need, I'm looking for a widgets.Whatsit[widgets.Cog]
In case it's been ten years since you used ServiceLoader, and who doesn't need a refresher:
apm#mara:~/tmp$ ls -R META-INF
META-INF:
MANIFEST.MF services
META-INF/services:
widgets.Whatsit widgets.Widget
apm#mara:~/tmp$ cat META-INF/services/widgets.Widget
widgets.Cog
widgets.Sprocket
apm#mara:~/tmp$ cat META-INF/services/widgets.Whatsit
widgets.Engine
widgets.FlyWheel
Stuff:
package widgets
trait Widget {
def turn(): Int
override def toString = s"Widget ${getClass.getSimpleName}"
}
class Cog extends Widget {
def turn() = 5
}
class Sprocket extends Widget {
def turn() = 10
}
trait Whatsit[+A <: Widget] {
def widget: A
override def toString = s"Whatsit ${getClass.getSimpleName} of $widget"
}
class Engine extends Whatsit[Cog] {
def widget = new Cog
}
class FlyWheel extends Whatsit[Sprocket] {
def widget = new Sprocket
}
Comparing Scala and Java. I was going to get a sense of how many LOC to getGenericInterfaces and find what you want in Scala, but then I put an end to the exercise.
package findwidgets
import reflect._
import reflect.runtime.universe._
import reflect.runtime.currentMirror
import scala.collection.JavaConverters._
import java.util.ServiceLoader
object Test extends App {
import widgets.{ Widget, Whatsit, Cog }
val ws = (ServiceLoader load classOf[Widget]).asScala
for (w <- ws) {
Console println s"Turn a ${w.getClass} by ${w.turn}"
}
val need = typeOf[Whatsit[Cog]]
for (x <- (ServiceLoader load classOf[Whatsit[Cog]]).asScala) {
val im = currentMirror reflect x
if (im.symbol.toType weak_<:< need)
Console println s"$x is what I need"
else
Console println s"$x is not what I need, I'm looking for a $need"
// java says:
if (classOf[Whatsit[Cog]] isAssignableFrom x.getClass)
Console println s"Um, OK, I'll take the $x"
else
Console println s"${classOf[Whatsit[Cog]]} isn't ass'able from ${x.getClass}"
}
}

How does one implement a Hadoop Mapper in Scala 2.9.0?

When I migrated to Scala 2.9.0 from 2.8.1, all of the code was functional except for the Hadoop mappers. Because I had some wrapper objects in the way, I distilled down to the following example:
import org.apache.hadoop.mapreduce.{Mapper, Job}
object MyJob {
def main(args:Array[String]) {
val job = new Job(new Configuration())
job.setMapperClass(classOf[MyMapper])
}
}
class MyMapper extends Mapper[LongWritable,Text,Text,Text] {
override def map(key: LongWritable, value: Text, context: Mapper[LongWritable,Text,Text,Text]#Context) {
}
}
When I run this in 2.8.1, it runs quite well (and I have plenty of production code in 2.8.1. In 2.9.0 I get the following compilation error:
error: type mismatch;
found : java.lang.Class[MyMapper](classOf[MyMapper])
required: java.lang.Class[_ <: org.apache.hadoop.mapreduce.Mapper]
job.setMapperClass(classOf[MyMapper])
The failing call is when I call setMapperClass on the Job object. Here's the definition of that method:
public void setMapperClass(java.lang.Class<? extends org.apache.hadoop.mapreduce.Mapper> cls) throws java.lang.IllegalStateException { /* compiled code */ }
The definition of the Mapper class itself is this:
public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
Does anyone have a sense of what I'm doing wrong? It looks to me like the type is fundamentally correct: MyMapper does extend Mapper, and the method wants something that extends Mapper. And it works great in 2.8.1...
Silly as it seems, you can work around the problem by defining the Mapper before the Job. The following compiles:
import org.apache.hadoop._
import org.apache.hadoop.io._
import org.apache.hadoop.conf._
import org.apache.hadoop.mapreduce._
class MyMapper extends Mapper[LongWritable,Text,Text,Text] {
override def map(key: LongWritable, value: Text, context: Mapper[LongWritable,Text,Text,Text]#Context) {
}
}
object MyJob {
def main(args:Array[String]) {
val job = new Job(new Configuration())
job.setMapperClass(classOf[MyMapper])
}
}