Object constructor and Delegates.notNull - kotlin

object WalletConfig {
init {
fill(HashMap<String, String>())
}
var clientUrl: String by Delegates.notNull()
private set
fun fill(settingMap: Map<String, String>) {
try {
clientUrl = settingMap["URL_CLIENT"] ?: ""
} catch(ex:Exception) { }
}
}
throw ex: fill: Load 'wallet.config' config file: java.lang.NullPointerException at ru.WalletConfig.setClientUrl(WalletConfig.kt)

The problem is caused by the miss ordered init block and property initializer. As stated in the answer about class initialization semantics. The init block is not the constructor - its code is included in the primary constructor.
The following example:
class OrderOfInits {
constructor() {
println("constructor")
}
init {
println("A")
}
init {
println("B")
}
init {
println("C")
}
}
val a = OrderOfInits()
Would print:
A
B
C
constructor
Property delegates initialization is also part of primary constructor. Their initialization order in constructor reflects the order they were declared in. In other words the init { fill(...) } initializer block invokes clientUrl setter which in turn tries to call Delegates.notNull() instance method. However the instance field holding the Delegates.notNull() was not yet set hence NPE.
To fix the problem you just need to reorder them like so:
object WalletConfig {
var clientUrl: String by Delegates.notNull()
private set
init {
fill(HashMap<String, String>())
}
...
}

Related

Why do I need to qualify references to an object inside my companion object with "Companion." from outside the class

I have a companion object with a named object inside of it, but unless I use Companion. kotlin can't resolve the reference
class Cls {
companion object {
object Obj {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // ok
println(Cls.Obj) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj) // ok
}
If I switch to val Obj = object { ... } then neither access works if I try to reference attr, but both allow me to reference Obj
class Cls {
companion object {
val Obj = object {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Obj) // ok
println(Cls.Companion.Obj) // ok
}
I don't understand this behavior. What's going on? My only guesses would be around static initialization ordering problems.
First, Answering the second question.
class Cls {
companion object {
val Obj = object {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Obj) // ok
println(Cls.Companion.Obj) // ok
}
Here the object{} is called as anonymous object which is assigned to the variable as val object It does not have any references.
When you check here, Cls.Obj is of type Any.
So you cannot access like Any.attr because Any is root of all Kotlin class, it will only have default fucntions like hashcode(), equals()...
Since it is an anonymous object, you cannot do type cast.So no way to access attr directly.
To access attr , you can acheive with interface.
interface Foo{
fun attrs():Int
}
class Cls {
companion object {
val Obj = object : Foo{
var attr = 1
override fun attrs(): Int = attr
}
}
}
fun main() {
println(Cls.Obj.attrs()) // Print attr value 1
}
Here is the compiled code looks like of this.
public final class Cls public constructor() {
public companion object {
public final val Obj: kotlin.Any /* compiled code */
}
}
When you see here, Obj is a variable inside which is of type Any.
In Kotlin, you can access variables inside companion object in both ways with or without Companion. Both will work.
println(Cls.Obj) // ok
println(Cls.Companion.Obj) // ok
In java , we need to access like,
Cls.Companion.getObj().
In Kotlin ,Companion word can be ignored. So accessing variables in companion object is the better one without using companion,like below.
println(Cls.Obj) // ok
Coming to First Question
class Cls {
companion object {
object Obj {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // ok
println(Cls.Obj) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj) // ok
}
Here you use object inside companion object, which is a nested object. This is similar to Nested static class in java, but not the same.
public final class Cls public constructor() {
public companion object {
public object Obj {
public final val attr: kotlin.Int /* compiled code */
}
}
}
The above one is the compiled code of the first one. When you check here, you have object inside companion object. But in your second question, you have made that Obj as variable. So you can directly call that variable. But here since it is a nested object, you should use companion keyword to access Obj.
Cls.Companion.Obj is the valid one.
When you access Obj like this Cls.Obj, the compiler checks for variable named 'Obj' inside that companion object. But there is no such variable because its an nested object.
And to make it clear,here is another example.
class Cls {
companion object {
object Obj {
val attr = 1
}
object Obj1{
val attr = 2
}
}
}
Hope it helps you.

Clean way to access outer class by the implementing delegate class

I was thinking about such case (accessing outer class which uses current class to implement some stuff):
interface Does {
fun doStuff()
}
class ReallyDoes: Does {
var whoShouldReallyDo: Does? = null
override fun doStuff() {
println("Doing stuff instead of $whoShouldReallyDo")
}
}
class MakesOtherDo private constructor(other: Does, hax: Int = 42): Does by other {
constructor(other: ReallyDoes): this(other.also { it.whoShouldReallyDo = this }, 42)
}
fun main(args: Array<String>) {
val worker = ReallyDoes()
val boss = MakesOtherDo(other = worker)
boss.doStuff()
}
Expected output:
Doing stuff instead of MakesOtherDo#28a418fc
But can't do that, because of error:
Error:(15, 79) Cannot access '' before superclass constructor
has been called
Which targets this statement: other.also { it.whoShouldReallyDo = this }
How can I (if at all) fix above implementation?
The reason for the error is other.also { ... = this } expression accesses this of type MakeOtherDo and is also used as argument to MakeOtherDo constructor. Hence, this will be accessed as part of MakeOtherDo (unary) constructor before this has been initialized as an instance of Does (super)class.
Since the assignment does not affect the initialization of the super class, you can executed it in the constructor of MakesOtherDo after the super class has been initialized.
class MakesOtherDo private constructor(other: Does, hax: Int = 42): Does by other {
constructor(other: ReallyDoes): this(other, 42) {
other.also { it.whoShouldReallyDo = this }
}
}
It took me a few minutes to decipher what you were doing above, and really the problem has nothing to do with delegates. You can simplify it down to this:
class Wrapper(var any: Any? = null)
class Test(val wrapper: Wrapper) {
constructor(): this(Wrapper(this)) // Cannot access "<this>" before superclass constructor has been called
}
The concept of "this" doesn't exist yet when we're still generating arguments for its constructor. You just need to move the assignment into the block of the constructor, which is code that's run after this becomes available:
class Test(val wrapper: Wrapper) {
constructor(): this(Wrapper()){
wrapper.any = this
}
}
Or in the case of your example:
constructor(other: ReallyDoes): this(other, 42){
other.whoShouldReallyDo = this
}

Hiding base class constructor parameters in Kotlin

I am trying to understand how to hide a base constructor parameter in a subclass in kotlin. How do you put a facade over a base constructor? This doesn't work:
import com.android.volley.Request
import com.android.volley.Response
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private fun hiddenListener() = Response.ErrorListener {
/* super secret listener */
}
...
}
I think I understand the problem:
During construction of a new instance of a derived class, the base
class initialization is done as the first step (preceded only by
evaluation of the arguments for the base class constructor) and thus
happens before the initialization logic of the derived class is run.
I'm trying to solve this problem for Volley, where I need my custom request to be be a Request so that it can be passed into a RequestQueue. It would be easier of RequestQueue took in some kind of interface but since it doesn't I have to subclass. There are other ways I can hide these complexities from the caller, but this limitation has come up for me other times in Kotlin and I'm not sure how to solve it.
I am not familiar with volley but I tried to come up with an example that should give you some insight how to solve your problem. What you can do is use a companion object:
interface MyListener {
fun handleEvent()
}
open class Base<T>(anything: Any, val listener: MyListener) { // this would be your Request class
fun onSomeEvent() {
listener.handleEvent()
}
}
class Derived(anything: Any) : Base<Any>(anything, hiddenListener) { // this would be your MyCustomRequest class
private companion object {
private val hiddenListener = object : MyListener {
override fun handleEvent() {
// do secret stuff here
}
}
}
}
So if you apply this to your problem, the result should look something like this:
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private companion object {
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
}
...
}
A different way would be to use a decorator, create your Request withing that decorator and just delegate the calls to it:
class Decorator(anything: Any) {
private var inner: Base<Any>
private val hiddenListener: MyListener = object : MyListener {
override fun handleEvent() { }
}
init {
inner = Base(anything, hiddenListener)
}
}
And once again for your example that would look like this:
class MyCustomRequest(url: String) {
private var inner: Request<String>
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
init {
inner = Request<String>(Request.Method.POST, url, hiddenListener)
}
...
}

Spek - Variable not initialized in test

The following code does not compile:
describe("something") {
context("when something") {
var a: SomeType
beforeEachTest {
a = someNewMutableObject
}
it("should do something") {
assertTrue(a.something()) // variable a not initialized
}
}
}
How would one get around this problem? What could i assign to the variable to get rid of the warning?
Just use the lateinit modifier on the variable that will be initialised before use.
describe("something") {
context("when something") {
lateinit var a: SomeType
beforeEachTest {
a = someNewMutableObject
}
it("should do something") {
assertTrue(a.something()) // variable a is okay to use here
}
}
}
PS. lateinit local variables are available from Kotlin 1.2 only
In Kotlin 1.1 you should just initialise it to a default value or null (make it a nullable type also).

Having a singleton use the value from initWithCoder instead of creating a new instance in Swift

I have a simple boolean variable in a function on which a set an observer to check when it changes:
var userValid: Bool{
didSet{
let valid=userValid ? "valid" : "not valid"
print("uservalid changed to \(valid)")
}
}
I set it to false in the init and then to true in the program: the initialiser is called twice once for the class and once for the subclass but I am alway checking the value in the class. So I am seeing the variable is set to true in the observer, but then when I check it in another function I find it at false without the observer to be ever called again.
As it comes out the problem seems to stem from the fact I initialise two times the class: once as a singleton and the other one with:
init?(coder aDecoder: NSCoder)
Of course I initialise the singleton with:
public class func sharedMapDelegate() -> MapDelegate {
struct Static {
static let instance : MapDelegate = MapDelegate()
}
return Static.instance
}
How may I return the value generated from the initWithCoder instead of creating a new one?
I think I have fixed it by changing the singleton to:
public class func sharedMapDelegate() -> MapDelegate {
struct Static {
static var instance : MapDelegate {
if let me = Factory.sharedFactory().mapHandler {
return me
} else {
Factory.sharedFactory().mapHandler=MapDelegate()
return Factory.sharedFactory().mapHandler
}
}
}
return Static.instance
}