I have 2 questions:
1) I'm trying to get the List menu in this program to appear either by calling scalac then scala or print it using the REPL but I'm a little confused because this uses packages. I tried to run this using
scalac Fruits.scala
scala bobsdelight\Fruits
but I get java.lang.NoClassDefFoundError: bobsdelights\Fruits wrong name: bobsdelights/Fruits)
If someone can please show me how to execute this script that would be great
2)I'm also trying to create a new Apple object by calling new Fruits.Apple in the REPL by loading the file first but I get:
error: type Apple is not a member of object Fruits
new Fruits.Apple``
This example is in the Programming In Scala book.
package bobsdelights
abstract class Fruit(
val name: String,
val color: String
)
object Fruits {
object Apple extends Fruit("apple", "red")
object Orange extends Fruit("orange", "orange")
object Pear extends Fruit("pear", "yellowish")
val menu = List(Apple, Orange, Pear)
}
REPL example:
$ scala
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.
scala> :pa bobsdelight.scala
Pasting file bobsdelight.scala...
scala> Fruits.menu
<console>:12: error: not found: value Fruits
Fruits.menu
^
scala> import bobsdelight._
<console>:11: error: not found: value bobsdelight
import bobsdelight._
^
scala> import bobsdelights._
import bobsdelights._
scala> Fruits.menu
res1: List[bobsdelights.Fruit] = List(bobsdelights.Fruits$Apple$#6c17c0f8, bobsdelights.Fruits$Orange$#260e3837, bobsdelights.Fruits$Pear$#88b76f2)
If you try to "run" a class with no main method:
$ scala bobsdelights.Fruits
java.lang.NoSuchMethodException: bobsdelights.Fruits.main([Ljava.lang.String;)
Idiom for runnable app:
object Fruits extends App {
object Apple extends Fruit("apple", "red")
object Orange extends Fruit("orange", "orange")
object Pear extends Fruit("pear", "yellowish")
val menu = List(Apple, Orange, Pear)
println(menu)
}
and
$ scalac bobsdelight.scala && scala bobsdelights.Fruits
List(bobsdelights.Fruits$Apple$#4f8e5cde, bobsdelights.Fruits$Orange$#504bae78, bobsdelights.Fruits$Pear$#3b764bce)
Related
I have written this code
import io.circe._, io.circe.generic.auto._, io.circe.parser._, io.circe.syntax._, io.circe.generic.extras._
implicit val config: Configuration = Configuration.default
case class Company(name: String)
case class Quote(average: Double)
case class Stats(price: Double)
#ConfiguredJsonCodec case class Bulk(company: Company, #JsonKey("advanced-stats") stats: Stats, quote: Quote)
val input = """{"AAPL": {"company": {"name": "Apple"},"advanced-stats": {"price":10},"quote": {"average":10}}}"""
val parsed = decode[Map[String, Bulk]](input)
When I try to execute this inside of ammonite I get an error
cmd5.sc:1: macro annotation could not be expanded (you cannot use a macro annotation in the same compilation run that defines it)
#ConfiguredJsonCodec case class Bulk(company: Company, #JsonKey("advanced-stats") stats: Stats, quote: Quote)
When I copy paste this code into a file and try to compile it then it gives compilation error
could not find Lazy implicit value of type io.circe.generic.extras.codec.ConfiguredAsObjectCodec
Edit:: Thanks to the answer below the code started to work on ammonite. it still doesn't compile when I copy paste it into a Scala file. I googled and changed the code to
object DefaultValues {
implicit val useDefaultValues = Configuration.default.withDefaults
}
import DefaultValues._
#ConfiguredJsonCodec
case class Bulk(
company: Company,
#JsonKey("advanced-stats") stats: Stats,
quote: Quote
)
but it still says
could not find Lazy implicit value of type io.circe.generic.extras.codec.ConfiguredAsObjectCodec[Bulk]
Have you enabled macro annotations? Scala 2.13 require flag that you can enable in Ammonite with:
interp.configureCompiler(_.settings.YmacroAnnotations.value = true)
in earlier versions of Ammonite which used Scala 2.12 and earlier you have to use
// replace with Scala version appropriate for your Ammonite
// \/
import $plugin.$ivy.`org.scalamacros:paradise_2.12.11:2.1.1`
The following Scala (2.12.12) code runs with the expected behavior. The ClassDef tree is defined using the toolbox, and a ClassSymbol is returned.
class MyObj
object MyObj {
def foo(x: Int): Int = x
}
object Test {
import ru._
def main(args: Array[String]): Unit = {
val objSymbol = ru.typeOf[MyObj].typeSymbol.companion // This is the most important line!
val tree = ClassDef(
Modifiers(),
TypeName("Program"),
List(),
Template(
List(Ident(TypeName("AnyRef"))),
noSelfType,
List(
DefDef(
Modifiers(),
termNames.CONSTRUCTOR,
List(),
List(List()),
TypeTree(),
Block(
List(
Apply(Select(Super(This(typeNames.EMPTY), typeNames.EMPTY), termNames.CONSTRUCTOR), List())
),
Literal(Constant(()))
)
),
DefDef(
Modifiers(),
TermName("fn"),
List(),
List(),
TypeTree(),
Apply(Select(Ident(objSymbol), TermName("foo")), List(Literal(Constant(10))))
)
)
)
)
val clsSymbol = Reflection.toolbox.define(tree).asInstanceOf[ClassSymbol]
}
}
However, the class MyObj is only serving the purpose of allowing us to get the symbol of the object via ru.typeOf[MyObj].typeSymbol.companion. I have some situations where an object does not have a companion class, and I would like to modify this code so that it works without the need for class MyObj.
Here is what I have tried so far:
Attempt 1.
val objSymbol = ru.typeOf[MyObj.type].typeSymbol
Produces the following error in the compiler. I don't know how to understand it, and can't find many mentions of this kind of error outside of the Scala language developer discussions.
Exception in thread "main" scala.tools.reflect.ToolBoxError: reflective compilation has failed:
Unexpected tree in genLoad: erp12.scala_cbgp.lang.MyObj.type/class scala.reflect.internal.Trees$TypeTree at: NoPosition
while compiling: <no file>
during phase: jvm
library version: version 2.12.12
compiler version: version 2.12.12
reconstructed args:
last tree to typer: TypeTree(class Int)
tree position: <unknown>
tree tpe: Int
symbol: (final abstract) class Int in package scala
symbol definition: final abstract class Int extends (a ClassSymbol with SynchronizedClassSymbol)
symbol package: scala
symbol owners: class Int
call site: constructor Program in class Program in package __wrapper$1$78b0f9d262f74777a2e9b5209fcd5413
Attempt 2.
currentMirror.staticModule(MyObj.getClass.getCanonicalName)
Also tried with variations:
runtimeMirror(getClass.getClassLoader) vs currentMirror
MyObj.getClass.getTypeName vs MyObj.getClass.getCanonicalName (same thing in this case)
This throw a ToolBoxError with value foo is not a member of object erp12.scala_cbgp.lang.MyObj$ which leads me to believe it is returning a different symbol from the one I need.
Attempt 3.
currentMirror.staticClass(MyObj.getClass.getCanonicalName)
Yields the same result as attempt 1.
Any guidance on what I am doing wrong would be much appreciated.
You were close.
The issue with attempt 1 is that ru.typeOf[MyObj.type].typeSymbol is the ClassSymbol of this object, not its ModuleSymbol. So try
ru.typeOf[MyObj.type].typeSymbol.asClass.module
instead. See details in Get the module symbol, given I have the module class, scala macro
The issue with attempts 2-3 is that MyObj.getClass.getCanonicalName is path.to.MyObj$ but this is a Java-style name, not Scala-style one. You can now try just to drop a dollar sign
currentMirror.staticModule(MyObj.getClass.getCanonicalName.stripSuffix("$"))
but this works not always. See details in In a scala macro, how to get the full name that a class will have at runtime? (with comments). So better would be
currentMirror.staticModule(
// Scala-style name i.e. path.to.MyObj
currentMirror.moduleSymbol(MyObj.getClass).fullName
)
or just
currentMirror.moduleSymbol(MyObj.getClass)
By the way, I'd write your tree with a quasiquote
val tree = q"""
class Program {
def fn = $objSymbol.foo(10)
}"""
although I remember that you prefer manual construction.
I executed this code block in a IntelliJ worksheet (Community Edition EAP 15#143.379.11 with Scala plugin 1.9.4 on JDK 1.8.0_66) ,
class Plant
class Fruit extends Plant
class Apple extends Fruit
class Box[T <: Fruit](var item: T) {
def get: T = item
def replace(item: T): Unit = this.item = item
}
val appleBox = new Box(new Apple)
println(appleBox.get) // error
and IntelliJ reported this error during worksheet compilation and stopped,
Error:(22, -59) side-effecting nullary methods are discouraged: suggest defining as `def get$$instance$$res0()` instead
println(appleBox.get);//
^
How do I disable this error or change it to warning and let me continue? I am using IntelliJ . Thanks
To avoid an error just remove println, Scala Worksheet will print the object for you.
val appleBox = new Box(new Apple)
appleBox.get
appleBox: Box[Apple] = Box#4109bbc4
res0: Apple = Apple#6e2e3a8b
PS: I do not get the error you are reporting in the latest EAP Scala Plugin (1.9.272)
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
*/
in Scala2.10.0 REPL
Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_13).
Type in expressions to have them evaluated.
Type :help for more information.
scala> case class A private(i:Int)
defined class A
scala> A(1)
res0: A = A(1)
But if compile
$ scala -version
Scala code runner version 2.10.0 -- Copyright 2002-2012, LAMP/EPFL
$ cat Main.scala
package foo
case class A private (i:Int)
object Main extends App{
println(A(1))
}
$ scalac Main.scala
Main.scala:6: error: constructor A in class A cannot be accessed in object Main
println(A(1))
^
one error found
A.apply(1) is compile error.
is this Scala2.10.0 REPL bug?
FYI Scala2.9.2 REPL is following
Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_13).
Type in expressions to have them evaluated.
Type :help for more information.
scala> case class A private(i:Int)
defined class A
scala> A(1)
<console>:10: error: constructor A in class A cannot be accessed in object $iw
A(1)
^
This definitely looks like a REPL bug.
Note that the constructor is correctly marked as private (in other words, new A(1) does not compile, as expected), it is only the factory (A.apply) that is wrongly public.
I see... You think you're calling the constructor when you write A(1). You're not. You're calling the factory added for you in the automatically generated (public) companion object and its public apply method.
Addendum
My day to be repeatedly wrong…
In the 2.10.0 REPL:
scala> object REPL { case class CC1 private(i: Int); val cc1_1 = CC1(23) }
<console>:7: error: constructor CC1 in class CC1 cannot be accessed in object REPL
object REPL { case class CC1 private(i: Int); val cc1_1 = CC1(23) }
The REPL has one huge semantic difference w.r.t. the ordinary compiler.
Consider what it means to be able to do this:
scala> val v1 = 23
v1: Int = 23
scala> val v1 = 42
v1: Int = 42
Could you do that in compiled Scala code? Of course not, it would be a prohibited double definition.
How does the REPL do this? In effect every line you enter is in a progressively more nested scope. The appearance of redefinition is actual shadowing. It's as if you did this:
object REPL1 {
val v1 = 23
object REPL2 {
val v1 = 42
object REPL3 {
// Next REPL line here...
}
}
}
So, how do you get companions? Put an explicit object (or other scope-forming construct) around them. And remember, no blank lines. The REPL will stop accepting input for a given "line" or "block" when you do.