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.
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.
In the code below I can access all overridden members of the abstract class, but not its own members.
interface Collection<T: Any> {
val count: Int
val isEmpty: Boolean
get() = count == 0
}
interface Heap<T: Any> : Collection<T> {
fun peek(): T?
}
abstract class AbstractHeap<T: Any>() : Heap<T> {
var elements: ArrayList<T> = ArrayList<T>()
override val count: Int
get() = elements.size
override fun peek(): T? = elements.firstOrNull()
...
}
class ComparableHeapImpl<T : Comparable<T>> :
AbstractHeap<T>() {
companion object {
fun <T : Comparable<T>> create(
elements: ArrayList<T>
): Heap<T> {
val heap = ComparableHeapImpl<T>()
heap.heapify(elements)
return heap
}
}
}
I cannot access elements as below
fun main() {
val array = arrayListOf(1, 12, 3, 4, 1, 6, 8, 7)
val test = ComparableHeapImpl.create(array)
val a = test.elements[0] // This won't work.
}
But in this code I wrote:
abstract class Test{
val i = 1
fun test(){ println("nothing")}
}
class Test1: Test(){
companion object {
val a = Test1()
fun create(): Test1 = a
}
}
fun main() {
val test = Test1.create()
test.test() // This works fine.
println(test.i) // And this works fine.
}
Everything works fine. I cannot make sense of this. Oh, and I am using android studio arctic firefox patch 2.
Your test variable here:
val test = ComparableHeapImpl.create(array)
is not of type AbstractHeap<Int>, it is of type Heap<Int> (by definition of ComparableHeapImpl.create). This is why you cannot access elements - it's not part of the Heap interface.
If you want to access the elements variable, you have several options:
make it part of the Heap interface
make create return AbstractHeap (or ComparableHeapImpl, which would be more logical for this factory function)
cast test to AbstractHeap or ComparableHeapImpl
Why do you want to access this property from outside, though? IMO, you should provide all the public methods/properties that make sense for the usage of your heaps in the Heap interface, but this one most likely should be private (or maybe protected).
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.
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.
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.