Instantiating the same scala class from main - scala

In Java I usually do something like:
class Hello {
public Hello() {
System.out.println("hello");
}
public static void main(String args[]) {
new Hello();
}
}
How do I do something similar in Scala? I start off with Hello being a Scala object like so:
object Hello {
// constructor goes here
def main(args: Array[String]): Unit = {
println("hello") // new Hello() would go here
}
}
but I can't instantiate that. If I change I change the object keyword to class then the scala compiler complains i.e.
class Hello {
println("hello")
def main(args: Array[String]): Unit = {
new Hello()
}
}
I know I'm probably on completely the wrong track here but I'd like to be put out of my misery.

Usually for this in Scala i use objects representing the application:
object Hello extends App {
println("hello")
}

I don't think you understand what a Scala object is. It is actually the equivalent of a Java singleton, where an anonymous class is created and instantiated in place.
If you would recompile the code to Java in this scenario:
object Hello {}
It would get something like:
public class Hello$ {
public static Hello$ $MODULE = new Hello$()
}
This is already a singleton, an equivalent of a val. You can even do:
val x = Hello; // x will be of type Hello.type

Related

scala - mock function and replace implementation in tests

I'm using scalatest and when I test my code, I want to replace an implementation of a function to return something else when running tests.
In JavaScript its really simple and I thought I could do the same in scala.
So what I want is something like this:
object Module {
private def bar(): Int = {
5
}
def foo(): Unit = {
println(bar())
}
}
And the test will be something like that (dont mind the syntax, you get the idea)
class Test extends FunSpec {
mock(Module.bar, () => 1)
describe("Test") {
it("Test") {
Module.foo() // will print 1
}
}
}
I have searched the internet and came across scala mock libraries but none of them seemed to be able to replace the implementation of a method.
In every library you have to defined your mock in the test and pass it on to the code, but I don't want to do that.
Is there anyway to achieve this?
Thank you.
You can't mock Object in Scala, because it's like a static class in java (which you can't mock either). (and you can't mock scala objects not in mockito nor scalamock (maybe in their next version)).
But, if you change your object Module to class Module, you can mock this function easily (using mockito):
val mockModule = mock[Module]
when(mockModule.bar()).thenReturn(1)
You can do a fake class that has that function and put the value you want, if you dont want to use mocks, like this:
trait SMT{
def bar: Int
}
class RealImpl extends SMT{
def bar: Int = 5
}
class FakeImpl extends SMT{
def bar: Int = 1
}

How to call an overriden method using reflection?

Consider we have the following:
class Base { def name = "Base" }
class Successor extends Base {
override def name = "Successor"
}
I have tried to do the following (took from How to call a superclass method using Java reflection):
import java.lang.invoke.{MethodHandles, MethodHandle, MethodType}
object TestApp {
def main(args: Array[String]) {
val a = new Successor;
val h1 = MethodHandles.lookup().findSpecial(classOf[Base],
"name",
MethodType.methodType(classOf[String]),
classOf[Successor]);
println(h1.invoke(a));
}
}
but I get a runtime exception:
java.lang.IllegalAccessException: no private access for invokespecial: class Successor, from TestApp$
I was told that it is possible that Java reflection may not work correctly for Scala. Is it true? Or I simply do something wrong?
Actually, you can NOT even do it in Java. Note, in the answer of "How to call a superclass method using Java reflection", it works because the Test extends the Base: public class Test extends Base {...}.
It looks like it is possible and Java reflection works for Scala as well, I just didn't read all answers for How to call a superclass method using Java reflection.
The following code works:
object TestApp {
def main(args: Array[String]) {
val a = new Successor;
val impl_lookup = classOf[MethodHandles.Lookup].getDeclaredField("IMPL_LOOKUP")
impl_lookup.setAccessible(true)
val lkp = impl_lookup.get(null).asInstanceOf[MethodHandles.Lookup];
val h1 = lkp.findSpecial(classOf[Base],
"name",
MethodType.methodType(classOf[String]),
classOf[Successor])
println(h1.invoke(a)) // prints "Base"
println(a.name) // prints "Successor"
}
}
Thanks to Jesse Glick for this solution.

class can't have main() in scala?

I'm a beginner of Scala.
In Calulator.scala file
class Calulator {
var brand: String ="HP"
def add(m:Int, n:Int):Int = m+n
}
In CalculatorTest.scala file
object CalulatorTest {
def main(args:Array[String]) {
val cal = new Calulator
println(cal.add(1,2))
}
}
Compile two scala files and run CalculatorTest. This works.
My question is can I make them as one scala file like Java?
In Calulator.scala file
class Calulator {
var brand: String ="HP"
def add(m:Int, n:Int):Int = m+n
def main(args:Array[String]) {
val cal = new Calulator
println(cal.add(1,2))
}
}
This doesn't work !!!
I googled it and looks like main() should be in object.
Is there a way to put them in one file to run main()?
To put them in one file use the concept of the 'Companion Object'.
The class and companion object must be in the same file and share the same name.
class Calculator {
var brand: String = "HP"
def add(m: Int, n: Int): Int = m + n
}
object Calculator {
def main(args:Array[String]) {
val cal = new Calculator
println(cal.add(1,2))
}
}
Further reading: http://docs.scala-lang.org/tutorials/tour/singleton-objects.html
The simple answer is No
a deeper answer is that the scala compiler refers to an object as static and class it refers as regular.
when you want to run Java program your main must be declared as static otherwise the JVM will not recognize it as your program entry point.
regards the question about is it possible to union both of them ,the answer is not because thats how the scala compiler works.
The compiler would create MyClass$.class for scala object and MyClass.class for scala class thats why you should never ever call your class something like :
class MyClass$ {
}
because it will override the companion object for MyClass.

Instantiate a java static inner class from a scala object

Per the title, this seems like it should be a standard operation, but googling so far has not yielded any results for me. Suppose I have a java class like the following:
public class Outer {
public static class Inner {
int x;
Inner(int x) {
this.x = x;
}
}
}
Now, suppose I have a scala object like the following:
object Blah {
def main(args: Array[String]) {
val v = new Outer.Inner(4) // doesn't work
}
}
Instead of compiling as expected, I receive a "type Inner is not a member of Outer" error.
Is there a way to make the above code work as expected?
I test your example and seems to be correct.
If you still have problems try this:
object Blah {
import correct_package.Outer.Inner
def main(args: Array[String]) {
val v = new Inner(4)
}
}

Main method in Scala

I wrote a Scala class and defined the main() method in it. It compiled, but when I ran it, I got NoSuchMethodError:main. In all the scala examples, I have seen, the main method is defined in an object. In Java we define the main method in a class. Is it possible to define main() in a Scala class or do we always need an object for this?
To answer your question, have a look on the following :
I made a scala class, compiled and decompiled it, and what I got is interesting.
class MyScalaClass{
def main(args: Array[String]): Unit = {
println("Hello from main of class")
}
}
Compiled from "MyScalaClass.scala"
public class MyScalaClass {
public void main(java.lang.String[]);
public MyScalaClass();
}
So it means that when the scala class is converted to java class then the main method of the scala class which in turn being converted to the main method in java class is not static.
And hence we would not be able to run the program because JVM is not able to find the starting point in the program.
But if the same code is done by using the 'object' keyword then:
Compiling the following:
object MyScalaClass{
def main(args: Array[String]): Unit = {
println("Hello from main of object")
}
}
Decompiling the following:
javap MyScalaClass$.class
Compiled from "MyScalaClass.scala"
public final class MyScalaClass$ {
public static final MyScalaClass$ MODULE$;
public static {};
public void main(java.lang.String[]);
}
Decompiling the following
javap MyScalaClass.class
Compiled from "MyScalaClass.scala"
public final class MyScalaClass {
public static void main(java.lang.String[]);
}
So here we got public static void main in MyScalaClass.class therefore the main method can be executed directly by the JVM here.
I hope you got your answer.
As Eugene said in a comment, there are no static methods in Scala. But watch this:
$ cat Echo.scala
object Echo {
def main( args:Array[String] ):Unit = args foreach println
}
$ scalac Echo.scala
$ javap Echo\$.class
Compiled from "Echo.scala"
public final class Echo$ {
public static final Echo$ MODULE$;
public static {};
public void main(java.lang.String[]);
}
$ javap Echo.class
Compiled from "Echo.scala"
public final class Echo {
public static void main(java.lang.String[]);
}
Note that the classfile for the Echo class (not Echo$, the object) does indeed have a public static void main method. Scala generates static methods for methods defined in objects for compatibility with Java.
However, I consider creating a main method in a Scala program an anachronism. Use the App trait instead; it's cleaner:
object Echo extends App {
args foreach println
}
When I want to test my code in intelligent idea scala editor, I simply create a companion object just below my class and put a main method in it. That's all. see an example:
class Colon {
class Cow {
def ^ (moon:Moon): Unit ={
println("Cow jumped over the moon")
}
}
class Moon{
def ^:(cow:Cow) = println("This cow jumped over moon too")
}
}
object Colon{
def main(args: Array[String]): Unit = {
val c:Colon = new Colon
val cow = new c.Cow
val moon = new c.Moon
cow ^ moon
cow ^: moon
moon.^:(cow)
}
}