can any one explain the following output. I have a simple Scala code like this..
object compOrNotTest {
def main(args: Array[String]) {
var emp = new Employee("tom", 20)
println(emp)
println(Employee.adult(emp))
Employee.printName("Roland", 38)
var emp2 = new Employee("Harry", 37)
Employee.printName(emp2)
}
}
class Employee(name: String, age: Int) {
val ageOfEmplyedd: Int = age
val nameEmp: String = name
override def toString() = this.name + " age : " + this.age
def printName() {
println("name is in Class " + nameEmp)
}
}
object Employee {
def adult(emp: Employee) = {
if (emp.ageOfEmplyedd > 18)
true
else
false
}
def printName(name: String, age: Int) = {
val emp1 = new Employee(name, age)
println("Name is : " + emp1.printName())
}
def printName(emp1: Employee) = {
//val emp1 = new Employee(name, age)
println("Name is : "+ emp1.printName())
}
}
And the output I am getting is
tom age : 20
true
name is in Class Roland
Name is : ()
name is in Class Harry
Name is : ()
My question is that why , when I am calling from Companion object I am getting only Name is : (). I am expecting something like Name is : name is in Class Roland. Please help me out to understand the how scala works in this case. Thanks a lot
The return type of Employee.printName (in class Employee) is Unit. This is because this function was declared using procedure syntax (a function declaration with no = sign in it, which has been deprecated and which will no longer be supported in a future version of Scala) that has an associated return type of Unit. The Unit value that is returned is represented in Scala as ().
The following function declarations are equivalent:
// Using (soon-to-be-deprecated) procedure syntax.
def printName() {
println("name is in Class " + nameEmp)
}
// Using an explicit return type.
def printName(): Unit = {
println("name is in Class " + nameExp)
}
// Using an inferred return type (note "=" in declaration). The last statement is the call
// to println, which returns Unit, so a return type of Unit is inferred.
def printName() = {
println("name is in Class " + nameExp)
}
If you wanted to return the string that was printed, you would need something like this:
def printName() = {
val s = "name is in Class " + nameEmp
println(s)
s
}
Or, using an explicit return type, instead of inferring it from the last statement:
def printName(): String = {
val s = "name is in Class " + nameEmp
println(s)
s
}
Related
I am trying to stub a case class which has structure similar to below code.
case class Employee[T](name:T) {
def greet(str:String):String = {
"Hi, "+ str + ":" + name
}
def farewell(str:String):String = {
"Bye, "+ str + ":" + name
}
}
However, when creating a stub like this:
val emp = stub[Employee[String]],
gives the following error:
type mismatch;
found : T
required: String
val emp = stub[Employee[String]]
How can i Stub this class.
Stubbing cases classes is usually avoided but assuming you are using ScalaMock try extending it first with some defaults, for example
class StrEmployee extends Employee[String](null)
val emp = stub[StrEmployee]
(emp.greet _).when("aa").returns("bb")
assert(emp.greet("aa") == "bb")
I'm just learning Scala, and I have these three files:
abstract class Animal() {
name
sound
}
class Dog(n : String) extends Animal {
name = n
val sound = "Boof"
}
trait Speaking extends Animal {
def speak(n : String, s : Sound) : String = {
println(s + "! I'm " + n + "!")
}
}
In my main method, I have the following code:
d = new Dog("Maddie") with Speaking
println(d.speak)
When I run this code, I get error: not found: value d
Put val before d if you haven't declared it before.
I think it should be something like this:
abstract class Animal() {
def name: String // You need a type(String) and a qualifier(def)
def sound: String // the same
}
class Dog(n : String) extends Animal {
// Type is not obligatory here, as it is inherited from Animal.
// But you still need a qualifier(val)
val name = n
val sound = "Boof"
}
trait Speaking extends Animal {
// This method doesn't need those params,
// since this trait extends Animal,
// so it has access to name and sound defined there.
def speak: String = {
sound + "! I'm " + name + "!"
}
}
Your main method remains the same.
Let's say I have:
object GLOBAL_OBJECT{
var str = ""
}
class A(_str: String){
GLOBAL_OBJECT.str = _str
}
and I would like to create 2 copies of GLOBAL_OBJECT (for tests), so I am using different classloader to create obj2:
val obj1 = new A("1")
val class_loader = new CustomClassLoader()
val clazz = class_loader.loadClass("my.packagename.A")
val obj2 = clazz.getDeclaredConstructor(classOf[String]).newInstance("2")
println("obj1.getSecret() == " + obj1.getSecret()) // Expected: 1
println("obj2.getSecret() == " + obj2.asInstanceOf[A].getSecret()) // Expected: 2
which results following error:
my.packagename.A cannot be cast to my.packagename.A.
IntelliJ Idea seems to do it correctly, I can run obj2.asInstanceOf[A].getSecret() in "expression" window during debug process without errors.
PS. I have seen similar questions, but I could not find any not regarding loading class from .jarfile.
You're not going to be able to get around Java's class casting, which requires strict typing, within the same ClassLoader. Same with traits/interfaces.
However, Scala comes to the rescue with structural typing (a.k.a. Duck Typing, as in "it quacks like a duck.") Instead of casting it to type A, cast it such that it has the method you want.
Here's an example of a function which uses structural typing:
def printSecret(name : String, secretive : { def getSecret : String } ) {
println(name+".getSecret = "+secretive.getSecret)
}
And here's sample usage:
printSecret("obj1", obj1) // Expected: 1
printSecret("obj2", obj2.asInstanceOf[ {def getSecret : String} ]) // Expected: 2
You could, of course, just call
println("secret: "+ obj2.asInstanceOf[ {def getSecret : String} ].getSecret
Here's full sample code that I wrote and tested.
Main code:
object TestBootstrap {
def createClassLoader() = new URLClassLoader(Array(new URL("file:///tmp/theTestCode.jar")))
}
trait TestRunner {
def runTest()
}
object RunTest extends App {
val testRunner = TestBootstrap.createClassLoader()
.loadClass("my.sample.TestCodeNotInMainClassLoader")
.newInstance()
.asInstanceOf[TestRunner]
testRunner.runTest()
}
In the separate JAR file:
object GLOBAL_OBJECT {
var str = ""
}
class A(_str: String) {
println("A classloader: "+getClass.getClassLoader)
println("GLOBAL classloader: "+GLOBAL_OBJECT.getClass.getClassLoader)
GLOBAL_OBJECT.str = _str
def getSecret : String = GLOBAL_OBJECT.str
}
class TestCodeNotInMainClassLoader extends TestRunner {
def runTest() {
println("Classloader for runTest: " + this.getClass.getClassLoader)
val obj1 = new A("1")
val classLoader1 = TestBootstrap.createClassLoader()
val clazz = classLoader1.loadClass("com.vocalabs.A")
val obj2 = clazz.getDeclaredConstructor(classOf[String]).newInstance("2")
def printSecret(name : String, secretive : { def getSecret : String } ) {
println(name+".getSecret = "+secretive.getSecret)
}
printSecret("obj1", obj1) // Expected: 1
printSecret("obj2", obj2.asInstanceOf[ {def getSecret : String} ]) // Expected: 2
}
}
Structural typing can be used for more than one method, the methods are separated with semicolons. So essentially you create an interface for A with all the methods you intend to test. For example:
type UnderTest = { def getSecret : String ; def myOtherMethod() : Unit }
One workaround to actually run some method from dynamically delivered object instead of casting it is to use reflection in order to extract particular method, from new class and then invoke it on our new object instance:
val m2: Method = obj2.getClass.getMethod("getSecret")
m2.invoke(obj2)
The class file that contains obj2.asInstanceOf[A].getSecret() should be reloaded by CustomClassLoader, too.
And you must not use any class that references to A unless you reload the class by the same class loader that reloads A.
I have code like this
object API {
val apiBaseUrl = "https://api.com/2/"
def getUserDetails(id: String, pass: String): Map[String, String] {
val apiRequestUrl = apiBaseUrl + "?id=" + id + "&pass=" + pass
}
}
This gives me error only classes can have declared but undefined members for line starting with def and error only declarations allowed here for line starting with val apiRequestUrl. But when i change the above code to(just put an equals sign after the method signature)
object API {
val apiBaseUrl = "https://api.com/2/"
def getUserDetails(id: String, pass: String): Map[String, String] = {
val apiRequestUrl = apiBaseUrl + "?id=" + id + "&pass=" + pass
}
}
there is no error. Is there a difference between the above 2 definitions?
Is there a difference between the above 2 definitions?
Yes. In Scala, you have to use an equals sign for method bodies that return a value. So your second code fragment is more correct.
The first code fragment is parsed like this, I believe:
object API {
val apiBaseUrl = "https://api.com/2/"
def getUserDetails(id: String, pass: String): Map[String, String]
{
val apiRequestUrl = apiBaseUrl + "?id=" + id + "&pass=" + pass
}
}
This explains the error about the missing body for getUserDetails and the error about the block { ... } where a declaration is expected.
If I would like to use Java's Externalizable interface in a Scala class, no problem,
import java.io.Externalizable
import java.io.ObjectInput
import java.io.ObjectOutput
class ExternalizableTestClass(
var str: String = "",
var int: Int = 52
)
extends Externalizable
{
// Scala version of null constructor for Externalizeable.
def this() = this("null construction value", 52)
override def toString : String
= "ExternalizableTestClass(str:" + str + ", int:" + int + ')'
override def writeExternal(out: ObjectOutput) {
out.writeUTF(str)
out.writeInt(int)
}
override def readExternal(in: ObjectInput) {
str = in.readUTF()
int = in.readInt()
}
}
It will also carry data through externalizing. Run this through a externalizing/de-externalizing test rig,
val obj = new ExternalizableTestClass("ohh", 87)
Returns,
After de-externalizing object: ExternalizableTestClass(str:ohh, int:87)
All good.
Add a subclass, then,
class ExternalizableTestSubclass(
str: String = "",
int: Int = 64
)
extends ExternalizableTestClass (
str,
int
)
with Externalizable
{
def this() = this("subclass null construction value", 74)
override def writeExternal(out: ObjectOutput) {
// Java way to externalize if there is a subclass
super.writeExternal(out)
}
override def readExternal(in: ObjectInput) {
// Java way to externalize if there is a subclass
super.readExternal(in)
}
}
It will also carry data through externalizing. Run this through a externalizing/de-externalizing test rig,
val obj = new ExternalizableTestSubclass("ohh", 87)
Returns,
After de-externalizing object: ExternalizableTestClass(str:ohh, int:87)
Note we're not seeing any null construction values (as I might hope, externalizable code is populating the class).
Rarely a use for subclasses that have no variation, so lets make it do something; add an abstract method to the super-class, realise in the sub-class, make it a toString so we see what is going on,
abstract class ExternalizableTestClass(
var str: String = "",
var int: Int = 52
)
extends Externalizable
{
def this() = this("null construction value", 52)
override def toString : String
= "ExternalizableTestClass(str:" + str + ", int:" + int + ')'
def methodVariedBySubclass : String
override def writeExternal(out: ObjectOutput) {
out.writeUTF(str)
out.writeInt(int)
}
override def readExternal(in: ObjectInput) {
str = in.readUTF()
int = in.readInt()
}
}
class ExternalizableTestSubclass(
str: String = "",
int: Int = 64
)
extends ExternalizableTestClass (
str,
int
)
with Externalizable
{
def this() = this("subclass null construction value", 74)
def methodVariedBySubclass : String
= "ExternalizableTestSubclass(str:" + str + ", int:" + int + ')'
override def writeExternal(out: ObjectOutput) {
super.writeExternal(out)
}
override def readExternal(in: ObjectInput) {
super.readExternal(in)
}
}
Run this through a serializing/deserializing test rig,
val obj = new ExternalizableTestSubclass("ohh", 87)
Returns,
After de-externalizing object: ExternalizableTestClass(str:ohh, int:87)
After de-externalizing object with methodVariedBySubclass: ExternalizableTestSubclass(str:subclass null construction value, int:74)
Oh dear. The toString() method defined on the base is as expected, but the method methodVariedBySubclass() (a toString()) is returning tthe null parameters.
What, you may wonder, was the situation before serialization? Answer:
Before de-externalizing object: ExternalizableTestClass(str:ohh, int:87)
Before de-externalizing object with methodVariedBySubclass: ExternalizableTestSubclass(str:ohh, int:87)
Ah.
Has anyone been here? Throw in some insider knowledge?
(I've tried some variations to see if they expose any mechanisms. Making the superclass non-externalizable, and calling from the subclass returns the same dissimilar results.)
Hah, I have an answer. It's nothing to do with Extenalizable, or Scala's abbreviated constructors (or inner classes, or name-mangling). It's a clash of identifiers fooling the Scala compiler. Rename all identifiers in the base class (or the subclass). You may want to refer to the answers to this question,
Scala style guideline for underscore in identifiers
For anyone interested, with this adjustment, the above is working code.
Bear in mind that all (known to me) Java serialization techniques are available, or can be made available, in Scala,
https://github.com/eishay/jvm-serializers/wiki