"Property must be initialized or be abstract" in init block when throwing an exception - kotlin

Why does kotlin report Property must be initialized or be abstract. The object construction is never finished, so it should not matter whether a is initialized or not. Could a case be demonstrated where this would be a problem?
class Foo {
private val a: Int
init {
a = 42
throw Exception()
}
}
fun main() {
Foo()
}
kotlin playground
However these work just fine
fun bar() {
throw Exception()
}
class Foo {
private val a: Int
init {
a = 42
bar()
}
}
fun main() {
Foo()
}
kotlin playground
class Foo {
private val a: Int = throw Exception()
}
fun main() {
Foo()
}
kotlin playground
Similar java code works as expected:
public class Test {
private static class Foo {
private final int a;
public Foo() throws Exception {
a = 42;
throw new Exception();
}
}
public static void main(String []args) throws Exception {
new Foo();
}
}

The question is very well answered in the below link.
Kotlin: why do I need to initialize a var with custom getter?
Essentially it boils down to having a backing field for every "val" (property) . If you can provide a backing field, you need not initialize the field. Below is a small example of it.
class Foo {
private val a: Int
get() = getValue()
}
fun getValue():Int {
throw Exception()
}
fun main() {
Foo()
}

Similar java code works as expected:
Java initializes fields to 0 (or null/false depending on type) by default. You can see it e.g. by printing a's value before the a = 42 line.
Kotlin doesn't, because this implicit initialization makes it too easy to forget to initialize a property and doesn't provide much benefit. So it requires you to initialize all properties which have backing fields.

It seems to be a compiler bug as Alexey suggested
There is similar issue posted on Kotlin bug tracer.

Related

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
}

Mock private property with mockk throws an excpetion

I'm using mockk for my testing in kotlin. But I can't seem to override a private property in a spy object.
I have this object
private val driverMapSnapshotMap: MutableMap<Int, SnapshotImage> = mutableMapOf()
in a class that I spy on using
viewModel = spyk(DriverListViewModel(), recordPrivateCalls = true)
But when I try to make it fill up with mock values I get an error
every {
viewModel getProperty "driverMapSnapshotMap"
} returns(mapOf(1 to mockkClass(SnapshotImage::class)))
The error I get
io.mockk.MockKException: Missing calls inside every { ... } block.
Any thoughts?
Here is a solution to access private fields in Mockk for classes( for objects it is even simpler )
class SaySomething {
private val prefix by lazy { "Here is what I have to say: "}
fun say( phrase : String ) : String {
return prefix+phrase;
}
}
#Before
fun setUp() = MockKAnnotations.init(this, relaxUnitFun = true)
#Test
fun SaySomething_test() {
mockkConstructor(SaySomething::class)
every { anyConstructed<SaySomething>() getProperty "prefix" } propertyType String::class returns "I don't want to say anything, but still: "
val ss = SaySomething()
assertThat( ss.say("Life is short, make most of it"), containsString( "I don't want to say anything"))
}
It is nearly impossible to mock private properties as they don't have getter methods attached. This is kind of Kotlin optimization and solution is major change.
Here is issue opened for that with the same problem:
https://github.com/mockk/mockk/issues/263
It should be
every {
viewModel getProperty "driverMapSnapshotMap"
} returns mock(DriverRemoteModel::class)

Scope of methods of an anonymous object - Kotlin

In Kotlin if I define a method on an anonymous object, sometimes I am able to access it, while other times I am not. This seems to have something to do with scoping rules, but I am not sure what.
In the code example below, the access to example3.field.method() will cause a compilation error. Interestingly, example2.field.method() compiles just fine.
What could be the explanation for the below behaviour?
class Example3 {
val field = object {
fun method() {}
}
}
fun showcase() {
val example1 = object {
fun method() {}
}
example1.method()
println(example1::class.qualifiedName)
class Example2 {
val field = object {
fun method() {}
}
}
val example2 = Example2()
example2.field.method()
println(example2::class.qualifiedName)
val example3 = Example3()
// example3.field.method() // won't compile
println(example3::class.qualifiedName)
}
From docs Object Expressions and Declarations:
Note that anonymous objects can be used as types only in local and
private declarations. If you use an anonymous object as a return type
of a public function or the type of a public property, the actual type
of that function or property will be the declared supertype of the
anonymous object, or Any if you didn't declare any supertype. Members
added in the anonymous object will not be accessible.
Demonstrated in code sample below:
class Example4{
val publicObj = object{
val x = 1
}
private val privateObj = object{
val x = 2
}
fun showcase(){
val scopedObj = object{
val x = 3
}
println(publicObj.x) // ERROR : unresolved reference: x
println(privateObj.x) // OK
println(scopedObj.x) // OK
}
}
Pawel gave the correct answer to your question, pointing to the documentation:
the actual type of that function or property will be the declared supertype of the anonymous object, or Any if you didn't declare any supertype.
But just adding that if you really need to access example3.field.method() you could declare a supertype to field in Example3:
interface MyInterface {
fun method()
}
class Example3 {
val field = object: MyInterface {
override fun method() {}
}
}
fun main() {
val example3 = Example3()
example3.field.method()
}

Method References to Super Class Method

How to use method references to refer to super class methods?
In Java 8 you can do SubClass.super::method.
What would be the syntax in Kotlin?
Looking forward to your response!
Conclusion
Thanks to Bernard Rocha!
The syntax is SubClass::method.
But be careful. In my case the subclass was a generic class. Don't forget to declare it as those:
MySubMap<K, V>::method.
EDIT
It still doesn't work in Kotlin.
Hers's an example in Java 8 of a method reference to a super class method:
public abstract class SuperClass {
void method() {
System.out.println("superclass method()");
}
}
public class SubClass extends SuperClass {
#Override
void method() {
Runnable superMethodL = () -> super.method();
Runnable superMethodMR = SubClass.super::method;
}
}
I'm still not able to do the same in Kotlin...
EDIT
This is an example how I tried to achieve it in Kotlin:
open class Bar {
open fun getString(): String = "Hello"
}
class Foo : Bar() {
fun testFunction(action: () -> String): String = action()
override fun getString(): String {
//this will throw an StackOverflow error, since it will continuously call 'Foo.getString()'
return testFunction(this::getString)
}
}
I want to have something like that:
...
override fun getString(): String {
//this should call 'Bar.getString' only once. No StackOverflow error should happen.
return testFunction(super::getString)
}
...
Conclusion
It's not possible to do so in Kotlin yet.
I submitted a feature report. It can be found here: KT-21103 Method Reference to Super Class Method
As the documentation says you use it like in java:
If we need to use a member of a class, or an extension function, it
needs to be qualified. e.g. String::toCharArray gives us an extension
function for type String: String.() -> CharArray.
EDIT
I think you can achieve what you want doing something like this:
open class SuperClass {
companion object {
fun getMyString(): String {
return "Hello"
}
}
}
class SubClass : SuperClass() {
fun getMyAwesomeString(): String {
val reference = SuperClass.Companion
return testFunction(reference::getMyString)
}
private fun testFunction(s: KFunction0<String>): String {
return s.invoke()
}
}
Don't know if it is possible to get the reference to super class's function, but here is an alternative to what you want to achieve:
override fun getString(): String = testFunction { super.getString() }
According to Bernardo's answer, you might have something like this. It doesn't have remarkable changes.
fun methodInActivity() {
runOnUiThread(this::config)
}
fun config(){
}
What is more, in the incoming 1.2 version you can use just
::config

kotlin function default arguments from java

given following Kotlin class:
class Foo {
public fun bar(i: Int = 0): Int = 2 * i
}
How should I call 'bar' function without any parameter from a java/groovy code?
def f = new Foo()
f.bar() //throws: java.lang.IllegalArgumentException: Parameter specified as non-null contains null
You can do this now in Kotlin. For your class method, use the #JvmOverloads annotation.
class Foo {
#JvmOverloads public fun bar(name: String = "World"): String = "Hello $name!"
}
Now simply call it from Java:
Foo foo = new Foo();
System.out.println(foo.bar());
System.out.println(foo.bar("Frank"));
Outputs the following:
Hello World!
Hello Frank!
I'll post the real answer shortly, but if anyone is wanting to do this from reflection, here is how the code would look. Much more complicated, but educational about how to use Kotlin reflection for KCallable.
Here is the class to call:
class Foo {
public fun bar(name: String = "World"): String = "Hello $name!"
}
Then we need a utility class in Kotin that can receive an instance of a class, a method from java reflection, and the parameters by name. This only works with non-primitives:
class KReflectHelper {
companion object {
#Suppress("UNCHECKED_CAST")
#JvmStatic fun <T> callKotlinMethodWithNamedParms(instance: Any, method: Method, parmMap: Map<String, Any>): T {
val callable: KFunction<T> = method.kotlinFunction as? KFunction<T> ?: throw IllegalStateException("Method is not a Kotlin method")
val unusedParms = HashSet(parmMap.keys)
val callableParms = hashMapOf<KParameter, Any?>()
callable.parameters.map { parm ->
if (parm.kind == KParameter.Kind.INSTANCE) {
callableParms.put(parm, instance)
} else if (parm.kind == KParameter.Kind.VALUE && parmMap.contains(parm.name)) {
unusedParms.remove(parm.name)
callableParms.put(parm, parmMap.get(parm.name))
} else if (parm.kind == KParameter.Kind.VALUE) {
if (parm.isOptional) {
// default value will be used!
} else {
throw IllegalStateException("Missing required parameter ${parm.name}")
}
} else {
throw IllegalStateException("Cannot call methods that are not direct instance methods")
}
}
if (unusedParms.isNotEmpty()) {
throw IllegalStateException("Unrecognized parameters passed to function: $unusedParms")
}
return method.kotlinFunction?.callBy(callableParms) as T
}
}
}
Now that static method can be called from Java, but it isn't so much fun. A code generator would really be required. Calling it from Kotlin is much easier and some frameworks (such as Klutter and Kovert) already use something along these lines.
Foo foo = new Foo();
System.out.println(foo.bar("Frank"));
Method barMethod = Foo.class.getMethod("bar", String.class);
Map<String, Object> parms = new HashMap<String, Object>();
parms.put("name", "David");
System.out.println(KReflectHelper.callKotlinMethodWithNamedParms(foo, barMethod, parms));
// now call using the default
parms.clear();
System.out.println(KReflectHelper.callKotlinMethodWithNamedParms(foo, barMethod, parms));
Ouput:
Hello Frank!
Hello David!
Hello World!