How does the #main annotation in Scala 3 w​ork? - scala

As I was learning Scala 3, I saw a new way to write main:
#main def main1 =
println("main1 printed something")
I checked source for #main, it is just
class main extends scala.annotation.Annotation {}
What is happening by using #main here?

#main isn't really doing anything. It's the Scala compiler which does everything. Scala compiler will look for any methods which are marked with #main and turn them into java (jvm) entry static void main method.
Scala also supports multiple #main . It will link every #main method to a single static void method in a different class.
Besides wiring #main method to a java entrypoint, Scala compiler also adds some basic argument parsing. For example , you could do:
#main def go(name:String, age:Int) = println(s"hello, $name ($age)")
and expect it to work via CLI when you pass the name and age.
So #main is just really a marker annotation.
Reference documentation: https://dotty.epfl.ch/docs/reference/changed-features/main-functions.html

Related

Cannot run scala in IntelliJ

I'm struggling with running Scala Hello World project using IntelliJ IDEA Scala plugin. The project is created without any problems but when I create function which should be run, the run button doesn't appear. I've got no idea why it doesn't work.
Version of IntelliJ - 2020.3.1 (Community Edition)
Version of Scala plugin 2020.3.18
I've created Scala/sbt project (I'd also tried Scala/IDEA)
Vanilla options (but I'd also tried other versions of JDK, Scala and sbt)
The run button is missing
My code is:
class Hello extends App {
println("Hello world")
}
I've tried creating Scala worksheet and It works.
When you extend App, it needs to be as object Main extends App, not class Main extends App.
See Scala 2.13 specification 9.5 (emphasis mine):
A program is a top-level object that has a member method main of type (Array[String])Unit
The main method of a program can be directly defined in the object, or it can be inherited. The scala library defines a special class scala.App whose body acts as a main method
As Suma mentioned in his answer, you should use object, and not class. The code of the Hello file should be:
object Hello {
def main(args: Array[String]): Unit = {
println("Hello world")
}
}
As stated in YOUR FIRST LINES OF SCALA. Please note that if you prefer to extend App, all of the statements will be executed, as stated in the last link:
The argument of the scala command has to be a top-level object. If that object extends trait scala.App, then all statements contained in that object will be executed; otherwise you have to add a method main which will act as the entry point of your program.
Which means you have another option:
object Hello extends App {
println("Hello world")
}
I have created a gif that shows an example.

Scala 'this' and 'self' not working in simple App

New to scala (using version 2.12.1) obviously from the title. I'm writing my first app in IntelliJ. I've read about the Scala equivalent in Java to this. I've tried this, self, classOf[] and IntelliJ is complaining and the code is not compiling even if I ignore IntelliJ. Here's what I have:
import ch.qos.logback.classic.Logger
object Main extends App {
val logger = Logger[Main]
}
Logger package is importing correctly in SBT. However it cannot resolve the symbol Main. I tried sticking it in a package to make it less ubiquitous and then doing something like Logger[me.justin.Main] but that also doesn't work.
I also thought maybe extending App was causing some problems but I think that's fixed in the scala version I'm using? Maybe it's not even applicable?
I'm all Googled out. Help please!
You're getting tripped up by how Scala's objects work. Let's say we had a class Foo and a companion object for same:
class Foo
object Foo
If we wanted a logger for the class, we'd do the obvious thing:
val logger = Logger[Foo] // `Foo` here is the type of the class.
But what if we wanted to refer to the type of the object? We have to disambiguate from the type of the class. The answer is to use the special type member on the object:
val logger = Logger[Foo.type] // `Foo.type` here is the type of the object.
So in your case:
val logger = Logger[Main.type]

Explain this behaviour of scala class

I was wondering about this behaviour of scala class which is shown in the code snippet. The execution of following code prints hi , my confusion is what goes on in the background that without any method and field definition the invocation of TestClass executes the bare code? Also why is such kind of bare code writing within a class is allowed ?
class TestClass {
if(true)
println("hi")
}
object TestObject extends App{
val ci = new TestClass
}
The body of a class, object or trait (except for method definitions) is its (primary) constructor. It's more complicated for classes and object extending DelayedInit (or App, which extends DelayedInit).
The special syntax of 'bare' code inside classes is Scala's equivalent of Java's initializers / anonymous constructors that use braces around the code. Both initializers in Java and the code in your Scala class are executed on object creation, which is what you do inside your TestObject when calling the TestClass constructor with new.

How to use members with default (package) or private access level in REPL?

I was trying to add some interactivity to my test/debug cycle, so I tried playing around with my classes from the Scala REPL. This works great but has the disadvantage that I cannot access package- and private-level members, that can be tested from a unit test (if the test is in the same package).
Can I "set" the package "context" of the Scala REPL?
I guess I could use reflection to access the members, but that's so much typing it would defeat the purpose of using the REPL in the first place.
I assume the class you are testing are written in Java as you have to go out of your way to create package only member in Scala.
In short, it's not possible. Each line in the REPL is wrapped into it's own package, so it won't be allowed to access another package-only member from any other package. Even though there is an undocumented system property to change the default package name prefix used for wrapping, the package name is still generated automatically by incrementing a number:
$ scala -Xprint:parser -Dscala.repl.naming.line=foo.line
scala> val x = 1
[[syntax trees at end of parser]]// Scala source: <console>
package foo.line1 {
object $read extends scala.ScalaObject {
// snip ...
object $iw extends scala.ScalaObject {
// snip ...
object $iw extends scala.ScalaObject {
// snip ...
val x = 1
}
}
}
Assuming this is something you do often, what you could do is create a file that makes the reflection easy to use and then load it into the REPL using :load command.
Do you mean that you cannot access members defined in the package object? You can import these members using
import mypackage._
or simply access them using the prefixed form mypackage.mymember(...).

In Scala static value initialization does not appear to be happening before the main method is called

My Scala version:
Scala code runner version 2.9.0.1 -- Copyright 2002-2011, LAMP/EPFL
Given this code in a file named Static.scala:
object Main extends App {
val x: String = "Hello, World!"
override def main(args: Array[String]): Unit = {
println(x)
}
}
When I run:
scalac Static.scala && scala Main
I see:
null
instead of:
Hello, World!
I thought that x was a static because it was defined in an object, and that it would be initialized prior to the main method being called.
What am I doing wrong? Thanks!
This happens because of how you used the App trait. The App trait uses the DelayedInit feature which changes how the class body (including field initialization) is executed. The App trait includes a main method which executes the class body after binding the args field to the arguments to the program. Since you have overridden main this initialization is not happening. You should not provide a main method when using the App trait. You should either put the application code directly in the class body or not inherit from the App trait.
Try
lazy val x = "Hello World"
That should give you the results you're expecting.
You are not support to have a main method on an object extending App. If you do override it, you'd better understand how, exactly, DelayedInit works. In particular, objects extending App do not have static initialization -- that's the whole point of App.