Getting a compile time error for the following classes in the same file
class FancyGreeting (greeting: String) {
//private var greeting: String=_;
def greet() = {
println( "greeting in class" + greeting)
}
}
object FancyGreeting {
def privateGreeting(f:FancyGreeting) : String = {
f.greeting;
}
}
error: value greeting is not a member of this.FancyGreeting
f.greeting;
The same works if i use the private variable greeting instead of the constructor
You need to denote the constructor parameter as a variable, like so:
class FancyGreeting (val greeting: String) {
//private var greeting: String=_;
def greet() = {
println( "greeting in class" + greeting)
}
}
object FancyGreeting {
def privateGreeting(f:FancyGreeting) : String = {
f.greeting;
}
}
You should write class FancyGreeting(private var greeting: String) { if you want to have the same behavior as when you use the line you commented out. The way you write it (i.e. class FancyGreeting(greeting: String) {) is only giving greeting as a parameter to the constructor, without making it a property.
This said, you should not use ";" to end the lines in Scala. Moreover, it is usually better to use val than var, if you can.
NOTE: this answer might be interesting for you.
Related
Primary goal
I want to use some static vals in a class so that I don't have to pass them as function parameters.
My approach
Since I want them to be static, I am declaring them in the companion object. But I cannot assign them values when I declare them, for some reasons. So I am following the below approach.
case class DemoParams(name: String)
class Demo {
def foo = {
println("Demo params name is: ", Demo.demoParams.name) // Works fine
anotherFoo(Demo.demoParams.name) // Throws NPE !
}
def anotherFoo(someName: String) = {
// some code
}
}
object Demo {
var demoParams: DemoParams = _ // Declare here
def apply() = new Demo()
def run = {
demoParams = DemoParams(name = "Salmon") // Define here
val demoObj = Demo()
demoObj.foo
}
def main() = {
run
}
}
Demo.main()
I am able to print Demo.demoParams but surprisingly, this throws a NullPointerException when I pass Demo.demoParams to another function, while running the Spark app on a cluster.
Questions
Firstly, is this the right way of declaring static values and defining them later? I would prefer to not use vars and use immutable vals. Is there a better alternative?
Second, could you think of any reason I would be getting a NPE while passing Demo.demoParams.name to another function?
Your code works fine and doesn't throw anything (after fixing a few compile errors).
But ... Don't do this, it's ... yucky :/
How about passing params to the class as ... well ... params instead?
case class Demo(params: DemoParams) {
def foo() = {
println("Demo params name is: " + params.name)
}
}
object Demo {
def run() = {
val demoParams = DemoParams(name = "Salmon")
val demoObj = Demo(demoParams)
demoObj.foo()
}
}
Not sure this is the best alternative, but consider using a trait, which still keeps you in the FP zone by avoiding the use of var:
case class DemoParams(name: String)
trait Demo {
val demoParams: DemoParams
}
Then just define it where you need it, and it's ready for use:
object MainApp extends App {
val demoObj = new Demo {
override val demoParams: DemoParams = DemoParams(name = "Salmon")
}
println("Demo params name is: ", demoObj.demoParams.name) // (Demo params name is: ,Salmon)
anotherFoo(demoObj.demoParams.name) // Salmon
def anotherFoo(name: String): Unit = println(name)
}
About the second question, without the actual code one can only guess (this sample code does not throw NPE). Probably somewhere you are using it without defining it previously, because var demoParams: DemoParams = _ just initializes demoParams to the default value of the reference type DemoParams, which is null in this case, and you get NPE when you try to access the name value of a null object. This is why using var is discouraged.
I am experiencing a very strange typing error when running the below code.
The goal of this code is to have a class that can combine other instances of this class with itself, producing the updated instance. (Perhaps I should prefer immutability and return copies, but that's another discussion).
IntelliJ does not complain until I attempt to run the code, then it crashes with
type mismatch found: mic.MyInternalClass
required: MyClass.this.MyInternalClass this.myVar =
this.myVar.combine(mic.myVar)"
IntelliJ Error Message
class MyClass(s: String) {
var myVar: MyInternalClass = new MyInternalClass(s)
def combine(mic: MyClass): MyClass = {
this.myVar = this.myVar.combine(mic.myVar)
this
}
class MyInternalClass(s: String) {
var myInternalVar: String = s
def combine(mic: MyInternalClass): MyInternalClass = {
this.myInternalVar += mic.myInternalVar
this
}
}
}
object App {
def main(args : Array[String]) {
var mc1: MyClass = new MyClass("dog")
var mc2: MyClass = new MyClass("cat")
mc1.combine(mc2)
println(mc1.myVar.myInternalVar)
println(mc2.myVar.myInternalVar)
}
}
Each instance's MyInternalClass is considered a separate type in Scala, so you can't mix this's and mic's MyInternalClass. If that's not what you want, instead of using MyClass#MyInternalClass everywhere it's better to move MyInternalClass declaration to the companion object:
// otherwise you'll need to write MyClass.MyInternalClass explicitly even inside MyClass
import MyClass.MyInternalClass
class MyClass(s: String) {
var myVar: MyInternalClass = new MyInternalClass(s)
def combine(mic: MyClass): MyClass = {
this.myVar = this.myVar.combine(mic.myVar)
this
}
}
object MyClass {
class MyInternalClass(s: String) {
var myInternalVar: String = s
def combine(mic: MyInternalClass): MyInternalClass = {
this.myInternalVar += mic.myInternalVar
this
}
}
}
I just found this link: Referring to the type of an inner class in Scala
It looks like the inner class method needs a special type like so:
def combine(mic: MyClass#MyInternalClass): MyInternalClass = {
Still learning the nuances of why this is the case.
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.
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
Naive question I believe, but all I find is just calling other constructors from constructors. I need to call a method. My class (beginning):
class ScopedIterator[T](val iter : Iterator[T])
{
private var had_next : Boolean;
private var value : T;
moveNext();
...
so I would like to have a constructor with single argument, and in such constructor call a method moveNext. That's all.
When I compile the code I get error:
error: abstract member may not have private modifier
private var had_next : Boolean;
and the same for value.
I changed it to:
class ScopedIterator[T]
{
private var had_next : Boolean;
private var value : T;
private var iter : Iterator[T];
def this(it : Iterator[T]) =
{
iter = it;
moveNext();
}
...
But now I get error on "iter=it":
error: 'this' expected but identifier found.
iter = it;
How to write such constructor in Scala?
The first problem is that your definitions of had_next and value are abstract: these members have no right-hand side.
Try instead:
class ScopedIterator[T](val iter : Iterator[T]) {
private var had_next : Boolean = _
private var value : T = _
...
}
Here, _ means "default uninitialized value". For example, the following works for me in the console:
class ScopedIterator[T](val iter : Iterator[T]) {
private var had_next : Boolean = _
private var value : T = _
init()
def init() : Unit = { println("init !") }
}
scala> new ScopedIterator(List(1,2,3).toIterator)
init !
resN: ScopedIterator[Int] = ...
The second problem ("'this' expected...") comes because in Scala, auxiliary constructors must always call another constructor as their first statement. So your constructor could start with this(), for instance. For more details, see Section 6.7 in Programming in Scala.
The default constructor is the one you define when you declare your class
Ex:
class greeting(name:String) { ... }
You can also define the default constructor to take no parameters like in your code
class greeting { ... }
Then you can add extra constructors. All constructors you add to the class need to call another constructor as the first statement of the constructor. If you omit that you get the "this expected but identifier found".
Let's see an example:
class classconstructor {
var iter:Int = 0
def this(it:Int) = {
this()
iter = it;
moveNext();
}
def moveNext() = {
println(iter)
}
}
object App
{
def main(args:Array[String])
{
val x = new classconstructor()
val y = new classconstructor(200)
}
}
In the code above
new classconstructor() does nothing because the empty constructor doesn't have body.
and
new classconstructor(200) executes the empty constructor + the new one where you can add extra code such as a call to moveNext() method. In this case this one prints 200 to the console.