Explain why import scala.Predef.String fails build - scala

I found very strange issue with Scala import.
I wrote sample class:
package test_scala_predef
object App extends App {
classOf[T]
println( "Hello World!" )
}
class T {
}
This class compiles without any errors.
But, if I add
import scala.Predef.String
then I get compilation errors:
[INFO] Compiling 1 source files to /home/uthark/src/_/test_scala_predef/target/classes at 1374028063588
[ERROR] /home/uthark/src/_/test_scala_predef/src/main/scala/test_scala_predef/App.scala:10: error: not found: value classOf
[INFO] classOf[T]
[INFO] ^
[ERROR] /home/uthark/src/_/test_scala_predef/src/main/scala/test_scala_predef/App.scala:11: error: not found: value println
[INFO] println( "Hello World!" )
[INFO] ^
[ERROR] two errors found
I have an idea, that after I add specific import from scala.Predef, then implict import of scala.Predef._ is not added. But I can't find anything about it in the Scala documentation. Can anyone point me to the relevant section in documentation?
I checked Scala Language Specification (PDF), section 12.5 covering scala.Predef but also didn't find any related.
I use latest stable scala version available (2.10.2 at the moment)

I found the answer in the sources.
https://github.com/scala/scala/blob/master/src/compiler/scala/tools/nsc/typechecker/Contexts.scala:
/** List of symbols to import from in a root context. Typically that
* is `java.lang`, `scala`, and [[scala.Predef]], in that order. Exceptions:
*
* - if option `-Yno-imports` is given, nothing is imported
* - if the unit is java defined, only `java.lang` is imported
* - if option `-Yno-predef` is given, if the unit body has an import of Predef
* among its leading imports, or if the tree is [[scala.Predef]], `Predef` is not imported.
*/
protected def rootImports(unit: CompilationUnit): List[Symbol] = {
assert(definitions.isDefinitionsInitialized, "definitions uninitialized")
if (settings.noimports) Nil
else if (unit.isJava) RootImports.javaList
else if (settings.nopredef || treeInfo.noPredefImportForUnit(unit.body)) {
debuglog("Omitted import of Predef._ for " + unit)
RootImports.javaAndScalaList
}
else RootImports.completeList
}
This answers my question.
The key sentence is this:
Exceptions: ... if the unit body has an import of Predef among its leading imports
Also, in chat on #scala irc it was suggested to create bug in Scala issue tracking system, so I did it. https://issues.scala-lang.org/browse/SI-7672

Related

What is the Main object when running a Scala script?

For example the following code:
object Test extends App {
val x = 100
println(Main.x+" "+x)
}
Seems invalid since it won't compile given there is no Main object define anywhere.
And effectively it doesn't compile in Scastie nor using a standard scalac compiler (version 2.13.4), nor if you run this code directly on the REPL.
However, if you save it to a file and then you run it using the scala command (same version as before); like a script, it runs without problems and produces the following output:
100 100
What is that Main object? When and why it was added?
From what I see scriptBody() is responsible for this behavior:
/** This is the parse entry point for code which is not self-contained, e.g.
* a script which is a series of template statements. They will be
* swaddled in Trees until the AST is equivalent to the one returned
* by compilationUnit().
*/
def scriptBody(): Tree = {
// remain backwards-compatible if -Xscript was set but not reasonably
settings.script.value match {
case null | "" => settings.script.value = "Main"
case _ =>
}
...
// pick up object specified by `-Xscript Main`
def mainModule: Tree = settings.script.valueSetByUser.map(name => searchForMain(TermName(name))).getOrElse(EmptyTree)
/* Here we are building an AST representing the following source fiction,
* where `moduleName` is from -Xscript (defaults to "Main") and <stmts> are
* the result of parsing the script file.
*
* {{{
* object moduleName {
* def main(args: Array[String]): Unit =
* new AnyRef {
* stmts
* }
* }
* }}}
*/
def repackaged: Tree = {
...
Basically your script body is forcefully rewritten into something that is
object Main {
// must contain main
}
We can confirm that -Xscript appearing in these methods indeed controls this behavior:
// test.scala
object Test extends App {
val x = 100
println(Main.x+" "+x)
println(Main.getClass)
new Exception().printStackTrace()
}
With defaults we see that "Main" is used and that code is rewritten to have Main as starting point (code reused existing object Test extends App to create it):
> scala test.scala
warning: 1 deprecation (since 2.13.0); re-run with -deprecation for details
100 100
class Main$
java.lang.Exception
at Main$.delayedEndpoint$Main$1(test.scala:5)
at Main$delayedInit$body.apply(test.scala:1)
at scala.Function0.apply$mcV$sp(Function0.scala:39)
at scala.Function0.apply$mcV$sp$(Function0.scala:39)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
at scala.App.$anonfun$main$1(App.scala:76)
at scala.App.$anonfun$main$1$adapted(App.scala:76)
at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:563)
at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:561)
at scala.collection.AbstractIterable.foreach(Iterable.scala:919)
at scala.App.main(App.scala:76)
at scala.App.main$(App.scala:74)
at Main$.main(test.scala:1)
at Main.main(test.scala)
...
If we specify Test as our main, Main is not generated and compilation fails
> scala -Xscript Test test.scala
test.scala:3: error: not found: value Main
println(Main.x+" "+x)
^
test.scala:4: error: not found: value Main
println(Main.getClass)
Behavior of e.g. Scastie is different as Scastie defines its own main and put your code into it, so this synthetic Main is never created (though Test was still tampered with).

How can I compile a Scala and LWJGL3 application?

I'm having a lot of trouble compiling a Scala program with LWJGL3. I suspect that I either don't understand Scala's import statement correctly, or I don't understand Scala's classpath correctly. I've placed the LWJGL3 Nightly download in an org folder at my project root. This is the error scalac gives me:
Minimum.scala:1: error: object opengl is not a member of package org.lwjgl
import org.lwjgl.opengl._
^
Minimum.scala:3: error: object glfw is not a member of package org.lwjgl
import org.lwjgl.glfw.GLFW._
^
Minimum.scala:4: error: object opengl is not a member of package org.lwjgl
import org.lwjgl.opengl.GL11._
^
Minimum.scala:5: error: object system is not a member of package org.lwjgl
import org.lwjgl.system.MemoryUtil._
^
(Plus lots of error: not found: value _______ errors because it couldn't find the various functions.)
Here's my code (in Minimum.scala at the project root):
import org.lwjgl.opengl._
import org.lwjgl.glfw.GLFW._
import org.lwjgl.opengl.GL11._
import org.lwjgl.system.MemoryUtil._
object Minimum {
def main(args: Array[String]): Unit = {
glfwInit()
long windowHandle = glfwCreateWindow(500, 500, "Hello, World!", NULL, NULL)
glfwMakeContextCurrent(windowHandle)
GL.createCapabilities()
glClearColor(0.0f, 1.0f, 0.0f, 0.0f)
while (!glfwWindowShouldClose(windowHandle)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glfwSwapBuffers(windowHandle)
glfwPollEvents()
}
glfwDestroyWindow(windowHandle)
}
}
I've also tried these import statements instead, which were suggested here:
import org.lwjgl._, glfw._, opengl._
import Callbacks._, GLFW._, GL11._
import org.lwjgl.system.MemoryUtil._
Finally, I'm compiling with this command:
scalac -classpath ".;org/lwjgl/*;org/lwjgl-egl/*;org/lwjgl-glfw/*;org/lwjgl-jawt/*;org/lwjgl-jemalloc/*;org/lwjgl-lmdb/*;org/lwjgl-nanovg/*;org/lwjgl-nfd/*;org/lwjgl-nuklear/*;org/lwjgl-openal/*;org/lwjgl-opencl/*;org/lwjgl-opengl/*;org/lwjgl-opengles/*;org/lwjgl-ovr/*;org/lwjgl-par/*;org/lwjgl-sse/*;org/lwjgl-stb/*;org/lwjgl-tinyfd/*;org/lwjgl-vulkan/*;org/lwjgl-xxhash/*" Minimum.scala
Which I've tried numerous variations on including omitting the *, adding *.jar, moving the lwjgl libraries to another folder, giving just the org/ directory rather than the complete list, and replacing the ; with :. This is essentially the command I used to compile a nearly identical Java application, which worked perfectly.
Does anyone know how I can get my program to compile?

How do I leveraging SLF4J varargs logging in Play2.1 framework?

SLF4J's varargs on the logging calls are quite useful in my Java work
Logger log = LoggerFactory.getLogger( getClass() );
log.debug( "Hello, {}. The current time is {}", "robert", new Date() );
Attempting to do this simple example in Play 2.1 Framework/Scala and I run into the compiler rejecting me.
import play.api._
import play.api.mvc._
import org.slf4j.LoggerFactory
object Application extends Controller {
val log: org.slf4j.Logger = LoggerFactory.getLogger(getClass())
def hb = Action {
val message = makeMessage()
// COMPILER HATES THIS: ambiguous reference compiler error here
log.info("Hello {}. The current time is {}", "robert", new java.util.Date() )
Ok(message)
}
def makeMessage(): String = { return "stuff" }
}
[dm2-server] $ compile
[info] Compiling 2 Scala sources to /Users/bobk/work/dm2-server/target/scala-2.10/classes...
[error] /Users/bobk/work/dm2-server/app/controllers/Application.scala:16: ambiguous reference to overloaded definition,
[error] both method info in trait Logger of type (x$1: String, x$2: <repeated...>[Object])Unit
[error] and method info in trait Logger of type (x$1: String, x$2: Any, x$3: Any)Unit
[error] match argument types (String,String,java.util.Date)
[error] log.info("Hello {}. The current time is {}", "robert", new java.util.Date() )
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
[error] Total time: 1 s, completed Jun 6, 2013 10:54:41 AM
What is that error and how do I overcome it to call through to the SLF4J API? If I can't do that, how can I use the Play 2.1 Logging Framework to get varargs on my logging calls? Something is not right in Scala-land.
What version of SLF4J are you using? If you can go back to 1.6.6 or later, you can avoid this issue in ambiguity. Those two signatures unfortunately look the exact same to scala and the compiler can't seem to differentiate which one you mean. The common suggestion is to roll back to a version of SLF4J (if even possible for you) where this overloaded method ambiguity will not exist. More info can be found at the links below:
https://groups.google.com/forum/?fromgroups#!topic/scala-language/ms4IVIu-xGw
https://github.com/typesafehub/scalalogging/issues/16
The "quick fix" for this is as follows:
Just force the last argument to be type Any and that resolves the compiler's issue(s) (and makes for slightly less code...)
logger.debug("hello {} / {} ", "Hello", "World":Any)
Or in your case:
log.info("Hello {}. The current time is {}", "robert", new java.util.Date():Any)

How do I refer to enclosing "this" in a Scala macro?

The following macro, extracted from a larger example, is supposed to create a tree with nothing but a reference to this:
def echoThisImpl(c:Context): c.Expr[Any] = {
import c.universe._
val selfTree = This(c.enclosingClass.symbol)
c.Expr[AnyRef](selfTree)
}
def echoThis: Any = macro CallMacro.echoThisImpl
But a call to echoThis such as
object Testing extends App {
val thisValue = CallMacro.echoThis
println(thisValue)
}
fails to compile, with the message
[error] /home/rafael/dev/scala/goose/goose-macros/src/test/scala/Testing.scala:8: type mismatch;
[error] found : <noprefix>
[error] required: Any
[error] val thisValue = CallMacro.echoThis
If I set the -Ymacro-debug-lite flag the generated tree is This(newTermName("<local Testing>")).
There are two options of achieving what you want:
1) Use This(tpnme.EMPTY). Currently this doesn't compile, so you'll have to use This(newTypeName("")) instead, but in RC1 this will be fixed.
2) Use This(c.enclosingClass.symbol.asModule.moduleClass). Currently this doesn't work, because of https://issues.scala-lang.org/browse/SI-6394, but in RC1 this will be fixed.

Why do I need semicolons after these imports?

I never really used Traits much in Scala so far, and I want to change this. I have this code:
import tools.nsc.io.Path
import java.io.File
trait ImageFileAcceptor extends FileAcceptor {
override def accept(f:File) = {
super.accept(f) match {
case true => {
// additional work to see if it's really an image
}
case _ => false
}
}
}
The problem is, when I compile with sbt, I keep receiving:
ImageFileAcceptor.scala:2: ';' expected but 'import' found.
If I add ; after the imports, the code compiles. Here's FileAcceptor:
import java.io.File
trait FileAcceptor extends Acceptable {
override def accept(f:File):Boolean = f.isFile
}
And here's Acceptable:
import java.io.File
trait Acceptable {
def accept(f:File):Boolean
}
I don't understand why I need semicolons after the imports.
Maybe the output of sbt is helpful:
[info] Building project tt 1.0 against Scala 2.8.1
[info] using sbt.DefaultProject with sbt 0.7.5 and Scala 2.7.7
When the scala compiler encounters a Macintosh line ending--being \r--the scala compiler will erroneously declare the need for a semi-colon, as Moritz so deduced. Section 1.2 of the Scala Reference Manual describe correct newline characters. I could not find in the Reference which character literals were considered as newlines. From experience, both Windows (\r\n) and Unix (\n) are acceptable. Presumably scala is strictly compatible with Java in this regard.