Why is my nested class not accessible? (Kotlin) - kotlin

I was trying to follow an example from the nested classes documentation: Kotlin docs - Nested and inner classes
So I tried:
fun main(){
var tester = Test()
println(tester.x) // 42
tester.Foo().bar() // compiler error - unresolved reference: Foo!!!
}
class Test {
var x:Int = 42
class Foo {
fun bar() = println("foobar!")
}
}
However, the nested class was not accessible.
I'm obviously missing something really obvious.

If you're not trying to create an inner class, then a nested class should be referenced like so:
fun main() {
var tester = Test()
println(tester.x) // 42
// Static reference
Test.Foo().bar() // foobar!
}
class Test {
var x:Int = 42
inner class Foo {
fun bar() = println("foobar!")
}
}
As #broot said in his comment:
Nested classes are static, so you don't create them from instances

Related

How to reference parameterized constructor in Kotlin?

So I have this definition:
sealed interface ParseResult<out R> {
data class Success<R>(val value: R) : ParseResult<R>
data class Failure(val original: String, val error: Throwable) : ParseResult<Nothing>
}
I want to wrap certain elements in a Success. And I know I can do it like this...
list.map{ParseResult.Success(it)}
But is there a way to use a constructor reference?
list.map(ParseResult::Success) //this won't compile
You can use a constructor reference if you add an import:
import somepackage.ParseResult.Success
Or even a typealias:
typealias Success<R> = ParseResult.Success<R>
Then you can do:
list.map(::Success)
The idea here is to make ParseResult.Success referrable by a simple name.
Not being able to do ParseResult::Success does look like a bug to me though. Compare:
class Outer {
class Nested
}
class OuterGeneric<T> {
class Nested
}
fun main() {
val x = Outer::Nested // works
val y = OuterGeneric::Nested // error
}

Parameterized Test in Kotlin usign mehtod source for nested test class

I may use case the class under test has many cases so it is divided into a structure of inner classes. I want to write parameterized test cases to reduce boiler plate and code duplication.
For this I wanted to go with the approach of method source.
Class under test
class UnderTest
{
testThisMethod(a:String,b:String?){
// Do something
externalInterface.call(a?:b)
}
}
Test Case structure
internal class A() {
private val externalService = mockk<ExternalService>
private val test: UnderTest(externalService)
// Some general tests
//---Position Outter
inner class A {
//--- Position A
inner class B {
//--- Position C
#ParameterizedTest
#MethodSource("provideArguments")
fun `with arguments external service create object`(
argument1: String,
argument2: String,
expected: String
) {
// Some code
verify {
externalService.call(expected)
//some more verification
}
}
}
}
}
To provide the argument provider method I tried placing it at positions and got following errors
Position outer: initialization error :Could not find factory method in class
Position A,B: compilation error: companion not allowed here
How can this be achieved?
Try using #TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class A() {
private val externalService = mockk
private val test: UnderTest(externalService)
// Some general tests
//---Position Outter
inner class A {
//--- Position A
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
inner class B {
//--- Position C
#ParameterizedTest
#MethodSource("provideArguments")
fun `with arguments external service create object`(
argument1: String,
argument2: String,
expected: String
) {
// Some code
verify {
externalService.call(expected)
//some more verification
}
}
}
}
}
Check here for more details

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
}

How can I use a variable in my inner class?

I have this code using Kotlin:
class A{
var myVariable:String?=null
constructor(myVariable:String){
this.myVariable = myVariable
}
init {
println("Success !")
}
inner class B{
init {
println(myVariable)
}
}
}
fun main(args:Array<String>){
var b = A("test").B // this does not work
}
And unfortunately it does not work I get:
Error:(20, 23) Kotlin: Nested class 'B' accessed via instance reference
Error:(20, 23) Kotlin: Classifier 'B' does not have a companion object, and thus must be initialized here
How can I solve my problem?
When you do:
A("test").B
You're saying "Fetch something from an instance of A" - in this case, it's a class. However, this isn't the syntax you're looking for in your case. You can get mostly anything, but getting a reference is a separate issue. If you want to get a function, the syntax is different from getting a field or calling a function. Although this isn't very important, bit might still be worth keeping that in mind.
Since B is an inner class, you're so far entirely correct that you need an instance of A first. But you also need an instance of B. When you initialize B, it's still "connected" to the parent class, which is why you can access outer variables without any problems. However, it's still an initializable class - and you need to initialize it.
So you need to initialize B as well. The Kotlin syntax for this is pretty nice (where as the syntax in Java is slightly horrible) - all you need to add is () at the end.
So you'll end up with this:
val b = A("test").B()
// ...
This is because it's an inner class. If you had a static inner class (in Kotlin, that's a class within a class without the inner keyword), the initialization would've been A.B() - A isn't initialized in those cases.
You can also split up the initialization:
val a = A("test")
val b = a.B();
Once you have the variable, it's exactly like every other variable - the only difference here is the initialization.
Try this:
class A{
var myVariable:String?=null
constructor(myVariable:String){
this.myVariable = myVariable
}
init {
println("Success !")
}
inner class B{
init {
println(myVariable)
}
}
}
fun main(args:Array<String>){
var b = A("test").B() // You have to call the constructor here
}
You should create an instance (call constructor) of class B before accessing its members:
fun main(args:Array<String>) {
val b = A("test").B()
b.someFunction()
}
class A {
var myVariable:String? = null
constructor(myVariable: String) {
this.myVariable = myVariable
}
init {
println("Success !")
}
inner class B {
init {
println(myVariable)
}
fun someFunction() {
myVariable = "set new value to the variable"
}
}
}

Kotlin, how to assign callback implementation to a variable

I'm trying to assign a callback implementation of an interface (defined inside a class A) to a variabile defined inside another class B. Let's say that class A has the interface OnSomethingHappens which defines a doSomething method.
Inside class B I've defined my callback variable like this:
private lateinit var callback:A.OnSomethingHappens
I need to create an instance of class A passing callback variabile to the constructor in this way:
myinstanceA = A(callback)
I'm trying to assign an instance of an anonymous class that implements A.OnSomethingHappens using this code:
callback = object : A.OnSomethingHappens {
override fun doSomething(..){
//here I put the implementation of this method
}
}
but the compiler says "expecting member declaration" for my callback variable and "name expected" for object.
What I'm doing wrong?
Instead, I'm able to define and at the same time assign the callback variable in this way:
private var callback = object : A.OnSomethingHappens {
override fun doSomething(..){
//here I put the implementation of this method
}
}
Why? Which are the differences and a possible solution?
I'm trying to assign an instance of an anonymous class that implements A.OnSomethingHappens using this code: ...
This should work, but only inside a method:
class B {
private lateinit var callback:A.OnSomethingHappens
fun someMethod() {
callback = object : A.OnSomethingHappens { ... }
}
...
}
Given the error message and that private var compiles (which doesn't inside a method), you are trying to set it directly in the body of the class instead:
class B {
private lateinit var callback:A.OnSomethingHappens
callback = object : A.OnSomethingHappens { ... }
...
}
This is illegal: the only code you can write there is member definitions and init blocks.
Also, if you can initialize callback directly where it's defined or inside init, there's no point to lateinit in the first place.
It's not obvious from the code snippets cut down to such small pieces, but your issue is that you're writing down the assignment inside the body of a class, but not inside a function.
Here's an example of a valid declaration and immediate assignment:
class A {
var x: X? = X()
}
Here's an example of an invalid assignment, which places an arbitrary expression in the body of a class:
class A {
lateinit var x: X
x = X() // expression placed inside the class body, invalid syntax
someFunction() // extra example, calling functions here is invalid in the same way
}
Instead, you could put this initialization inside a function:
class A {
lateinit var x: X
fun initializeX() {
x = X()
}
}
Or inside an initializer block (in this case, you don't even need lateinit):
class A {
var x: X
init {
x = X()
}
}
While I couldn't explain how to solve your exact problem, because I can't quite understand what code is in which class, I hope these examples and explanation helped.
Hmm, let me propose a variant. It's more simple for me:
import android.util.Log
class SomeClass {
fun mainMethod() {
ClassWithCallback(
{ myBackValue: String ->
logMyString(myBackValue)
}
)
//simplify
ClassWithCallback({ logMyString(it) })
}
private fun logMyString(myBackValue: String) {
Log.d("SomeClass", myBackValue)
}
}
class ClassWithCallback(private val myCallBack: (myBackValue: String) -> Unit) {
init {
// we do something here and back it by callback
val myString = "Hello! Pass me back!"
myCallBack.invoke(myString.toUpperCase())
}
}
Using Kotlin lambdas. Hope this will help you.