How to use a variable from another class in Kotlin? - kotlin

I just have a (hopefully) simple question. How do I make a variable in one class that can be accessed by another class in Kotlin?
Class A:
var isBlue = 1
Class B:
if isBlue==1 then ...

class A
class A {
var isBlue = 1
}
class B
class B {
var classA = A()
fun demo(){
classA.isBlue//get A member
}
}
hope this helps.

you can either create an instance of the object and access the property like this
ClassA().isBlue
or inherit the class and access the attribute like this.
ClassB:ClassA{ fun someFn(){if (isBlue == 1) do something}}

In java , just declare with " static " , no need to call class name , in Kotlin need to call class name , but null pointer exception , Such headache problem

Related

Is it possible to nest an enum contains class's properties within an open class?

I've read this thread, it doesn't address my specific case.
Here's my minimal case:
open class BaseCase() {
lateinit var txtNode: UiObject
enum class TextType(val field: UiObject) {
PlainText(txtNode)
}
}
But there's error:
I was wondering if it is possible in Kotlin?
The problem is that txtNode is an instance variable. Different BaseCase instances could have different values. So the enum cannot know which one of them to take.
Let's for simplicity say txtNode is a String instead of an UiObject
Then how would the following code work?
val a = BaseCase()
a.txtNode = "test"
val b = BaseCase()
b.txtNode = "test2"
val c = BaseCase.TextType.PlainText
would c have "test" or "test2" as field? It simply isn't possible.
that's because enum class are final static classes ---> you cannot access non static variables.
for testing -> if you move your variable to companion object the code will work

Koin - How to generify Singleton creation?

I have a class InteractorCache<T> that I would like to inject in different places using Koin.
I would like to create a singleton instance of that class based on the type T. So if I have 10 types T, I would like 10 different singletons.
So far I managed to do the above with the following code (this is an example with only 2 types, A and B):
val interactorAModule = module {
factory {
InteractorA(get())
}
}
val aCache = module {
single(named("A")){
InteractorCache<List<A>>()
}
}
val interactorBModule = module {
factory {
InteractorB(get())
}
}
val bCache = module {
single(named("B")){
InteractorCache<List<B>>()
}
}
This works but there is a lot of repetition as I have to create a new cache module (aCache, bCache) every time I create a new type. I would like to be able to do something like this instead:
val cacheModule = module{
single<T>{
InteractorCache<T>()
}
}
so there is only 1 declaration that works for any type T.
Is there a way to do this in Koin?
Although this is late but the idea of making generic or T a singleton is bad idea, when you declare a class singleton it will run a single instance, so runtime error would be InteractorCache() is incompatible or mismatched to InteractorCache() as the first class you would assign the T for example the class A InteractorCache() it would be fixed instance of A and cannot anymore assign to class B.

Subclass var initialization step and OOP structure design

The abstract super class Parent has abstract method extract(Int), getting the value a from primary constructor, and submit it to that method extract(a).
abstract class Parent ( val a : Int ) {
abstract fun extract ( i : Int )
init {
// call overriden extract(Int)
extract ( a )
}
}
The sub class Child defines the method extract(Int), sending the value b to the Parent's constructor, then the super class Parent calling extract(Int) to set that value to Child's variable x.
class Child ( b : Int ) : Parent ( b ) {
// initialize x variable to -1
var x : Int = -1
override fun extract ( i : Int ) {
// set x to given int
x = i
}
}
Testing:
println ( Child ( 10 ).x )
And got:
-1
Now, try adding init{} of the sub class Child
init {
x = -2
}
Testing again:
println ( Child ( 10 ).x )
And got:
-2
Seemingly, the init{} of sub class Child is done after the super class Parent's construction.
Should the extract(Int) be overridden ann called by all sub classes, rather than by the super class?
I am not sure what you mean by "super class Child", but it seems you may be confused of the order of derived classes. Here is a really good example that shows the order. It has a code snippet that you can run on the site.
Generally speaking this kind of initializer interaction is frowned upon, since the exact order of operations, while well defined, is often counter-intuitive.
Specifically, what I believe is happening here, might be more clear using the more verbose explicit-constructor syntax in kotlin. You're code is an abbreviated version of this (note, this is legal kotlin):
abstract class Parent {
val a: Int
constructor(a: Int){
this.a = a
extract(a)
}
abstract fun extract ( i : Int )
}
class Child: Parent {
var x : Int
constructor(b: Int): Parent(b) {
//super.constructor(b) fires here
// initialize x variable to -1
x = -1
}
override fun extract (i : Int) {
// set x to given int
x = i
}
}
thus, as I hope is now a little more clear, a pseudo-call-trace is like this:
enter Child.constructor(10)
enter Parent.constructor(10)
assign 10 to this#Parent.a
enter this.extract(10) => V-Table resolves Child.extract()
assign 10 to this#Child.x
extract returns
Parent.constructor returns
assign -1 to this#Child.x this is probably your point of confusion
Child.constructor returns
What you can do
Generally speaking, when you encounter confusing initialization flows, the answer on the JVM is to formalize the complex initialization in another method, rather than in more init or constructors.
In kotlin the simplest way to do this --and a strategy used by many many libraries-- is to create a static factory method.
abstract class Parent(val a: Int) {
//...
}
class Child private constructor(var x: Int): Parent(x) {
companion object {
fun makeChild(unextracted: Int) {
val extracted = extract(unextracted)
return Child(extracted)
}
// a first good step is to make `extract` referentially transparent
// aka pure
// IE all of its function is provided in its return type
fun extract (i : Int): Int {
return i //do appropriate transforms.
//note, if you need multiple return values here, consider Pairs or Triples.
}
}
}
Note, kotlin provides some syntax sugar for this, you can override the invoke operator:
class Child { companion object { operator fun invoke(x: Int) { ... } } }
which means that instead of makeChild (eg Child.makeChild(10)) to call your factory function you to use ~constructor syntax (Child(10)).
Even more generally, if you find yourself running into this problem under an IOC container which, for whatever reason, must use initializer flow, I would encourage you to refactor your IOC consumers to use old-fashioned java factories. I'll need more details to elaborate here.

is it possible to add a template to the getter/setter of a data class?

for example , I want to change all setters this way:
this.a = StringUtils.trim(a);
If it's a java bean, I can do this by modifying the code generating template of the ide. But Intellij seems not support to atomically add getter/setter for kotlin data class.
Is there a way to do this?
There is not a way to do this as of Kotlin 1.1.
A Kotlin data class, for the most part, is a class "to do nothing but hold data".
I think the closest you can get is to validate your data upon class initialization and make your data class properties read-only values. e.g.:
data class Data(val a: String) {
init {
require(a == a.trim())
}
}
The following won't throw an exception:
val a = Data("ab")
val b = a.copy(a = "abc")
While the following will:
val c = a.copy(a = "abc ")
It looks like if you declare the property as private, you can create your own getter/setters for accessing it. This example works for me.
fun main(args: Array<String>) {
var t = test("foo")
t.setHello("bar")
println(t)
}
data class test(private var hello: String) {
fun setHello(blah: String) {
this.hello = blah
}
}
But you will still have an issue when the property is passed in to the constructor. You will probably need to rethink how you are doing this, either declaring the field private and trimming it in the getter, or not using a data class for this instance.

Why can't I access private class methods in the class's companion object in Scala?

I'm working on a homework assignment for my object oriented design class, and I'm running into trouble with Scala's companion objects. I've read in a few places that companion objects are supposed to have access to their companion class's private methods, but I can't seem to get it to work. (Just as a note, the meat of the assignment had to do with implementing a binary search tree, so I'm not just asking for answers...)
I have an object that is supposed to create an instance of my private class, BstAtlas (Bst is also defined in the Atlas object, took it out for clarity):
object Atlas {
def focusRoom(newRoom:Room,a:Atlas):Atlas = a.helpFocusRoom(newRoom);
abstract class Atlas {
...
protected def helpFocusRoom(n:Room):Atlas;
...
}
private class BstAtlas(bst:Bst) extends Atlas {
...
protected def helpFocusRoom(newRoom:Room):Atlas = ...
// uses some of bst's methods
...
}
}
But when I go to compile, I get the following error:
Question23.scala:15: error: method
helpFocusRoom cannot be accessed in
Atlas.Atlas
a.helpFocusRoom(newRoom);
The function helpFocusRoom needs to be hidden, but I don't know how to hide it and still have access to it inside of the companion object.
Can anyone tell me what I'm doing wrong here?
The problem is that classes and companion objects can't be nested like that. To define a companion object, you need to define the class outside of the object's body but in the same file.
Companion objects should be next to their real object, not containing it:
object Example {
class C(val i: Int = C.DefaultI) { }
object C { protected val DefaultI = 5 }
}
scala> (new Example.C).i
res0: Int = 5
scala> Example.C.DefaultI
<console>:11: error: value DefaultI cannot be accessed in object Example.C
Example.C.DefaultI
Alternatively, you can alter the scope of the protected keyword to include the enclosing object:
object Example {
def value = (new D).hidden
class D(val i: Int = 5) {
protected[Example] def hidden = i*i
}
}
scala> Example.value
res1: Int = 25
but here you ought not name the outer object the same thing as the inner class or you'll have trouble referring to it from within the class.