Kotlin delegate with `by` but create delegate *inside* delegator - kotlin

I want to use Kotlin delegation but I don't want to create the delgate outside the delegator. All the samples on delegation all look like this:
interface Worker {
fun doWork()
}
class Supervisor(workerDelegate: Worker) : Worker by workerDelegate {
}
class Delegate : Worker {
override fun doWork() {
// actual work
}
}
fun main() {
val delegate = Delegate()
val supervisor = Supervisor(delegate)
supervisor.doWork() // delegates to delegate
}
But I want to create the Delegate inside the Supervisor. Something like this:
class Supervisor : Worker by workerDelegate {
init {
val workerDelegate = Delegate()
}
}
Is something like this possible?

I suppose what you want is this:
class Supervisor : Worker by Delegate(){
}

just use a private constructor.
class Supervisor private constructor(workerDelegate: Worker) : Worker by workerDelegate {
constructor() : this(Delegate())
}
fun main() {
val delegate = Delegate()
val supervisor = Supervisor()
supervisor.doWork() // delegates to delegate
}

You should understand 2 things:
(..., some:IFace) : IFace by some working only with ctor parameter and only during creation (!) not after creation, it's not "lazy" and it not bind "field" or "property" it binds instance that was given at creation. So! It's not "delegation" in expected way it's just hint to compiler to substitute all IFace calls to instance that is already in stack.
while init{...} is a part of construction logic of class it works on members of class, but cannot replace parameters that was already processed from ctor in by operand.
The most advanced way is just to create "static" factory method to provide some logic to evaluate parameter for ctor.
Assume all this things said before here :
package codes.spectrum.serialization_json.excel
import io.kotlintest.shouldBe
import io.kotlintest.specs.StringSpec
class ItIsNotWorking : StringSpec() {
interface IDo {
fun doIt(): Int
companion object {
val STUB = object :IDo {
override fun doIt(): Int {
error("I am just stub")
}
}
}
}
class Do1 : IDo {
override fun doIt() = 1
}
class Do2 : IDo {
override fun doIt() = 2
}
// i try to make it as parameter in ctor but as var, wishing that it will bind it each call,
// not just during construction
class SuperDo private constructor(param:Int, var doiter: IDo):IDo by doiter{
// imagine that at constructor point you cannot still decide what IDo impl you require
constructor(param: Int) : this(param, IDo.STUB)
init {
// here i try some logic to lately (after construction) to setup doiter
if(param % 2 == 1){
doiter = Do1()
}else{
doiter = Do2()
}
}
}
init {
// that is my expectations
"When with 1 it will be Do1" {
SuperDo(1).doiter.doIt() shouldBe 1 // ok!!!
SuperDo(1).doIt() shouldBe 1 // fail!!!
}
"When with 2 it will be Do2" {
SuperDo(2).doiter.doIt() shouldBe 2 //ok!!!
SuperDo(2).doIt() shouldBe 2 //fail!!
}
// Uffff!!!! It's not working at all (!!!)
}
class NotSuperDo private constructor(val doiter: IDo):IDo by doiter{
// imagine that at constructor point you cannot still decide what IDo impl you require
constructor(param: Int) : this(buildDoiter(param))
companion object {
fun buildDoiter(param: Int) : IDo =
if(param % 2 == 1){
Do1()
}else{
Do2()
}
}
}
init {
// that is my expectations
"not-super When with 1 it will be Do1" {
NotSuperDo(1).doiter.doIt() shouldBe 1 // ok!!!
NotSuperDo(1).doIt() shouldBe 1 // ok!!!
}
"not-super When with 2 it will be Do2" {
NotSuperDo(2).doiter.doIt() shouldBe 2 //ok!!!
NotSuperDo(2).doIt() shouldBe 2 //ok!!
}
// It worked! But it still just better constructor - not case to substitute delegated iface
}
}

Related

Mockito: How to mock lambda callback? what is the type? (Kotlin)

I have two class TestTarget, MockTarget and test code below. If the TestTarget has two functions with same name and same count of parameter, the any() is ambiguous. I need to assign the type to any(ClassType). But what is the type of () -> Unit? I have tried Function0 and it doesn't work. Can anyone help?
Class TestTarget:
Class TestTarget(private val mockTarget: MockTarget) {
fun testFunction() {
// some logic to be tested.
// call mockTarget.doSomething.
}
}
Class MockTarget
Class MockTarget {
fun doSomething(callback: () -> Unit) {
// some logic here.
}
fun doSomething(listener: OtherType) {
// Test code works without this function.
}
}
Test Code:
// setup mocks.
#Test
fun `verify testFunction`() {
`when`(mockTarget.doSomething(any())).thenAnswer { invocation ->
// callback here.
}
}
Replace org.mockito.Mockito with org.mockito.kotlin.*
and you can code like this
val anyLambda = any<() -> Unit>()
val anyListener = any<OtherType>()

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
}

Get a reference to the class of the calling function

When I have two classes (A and B) and A has a function called myFunA which then calls myFunB (inside of class B), is it possible for code in myFunB to obtain a reference to the class A that is used to call myFunB? I can always pass the reference as a parameter but I am wondering if Kotlin has a way of allowing a function to determine the instance of the parent caller.
class A {
fun myFunA() {
val b = B()
b.myFunB() {
}
}
}
class B {
fun myFunB() {
// Is it possible to obtain a reference to the instance of class A that is calling
// this function?
}
}
You can do it like this:
interface BCaller {
fun B.myFunB() = myFunB(this#BCaller)
}
class A : BCaller {
fun myFunA() {
val b = B()
b.myFunB()
}
}
class B {
fun myFunB(bCaller: BCaller) {
// you can use `bCaller` here
}
}
If you need a reflection-based approach, read 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)
}
...
}

Is there a way to verify that a top-level function passed as a dependency to a class has been called during testing?

I have a class that receives a function allowing it to display things on the UI during a failure case. What's the best way that I can verify that the function is called in my test?
MyClass(private val uiPrinter: (String) -> Unit) {
fun foo() {
// do some stuff
uiPrinter("printing from foo!")
// do some more stuff
}
}
MyClassTest() {
val testUiPrinter: (String) -> Unit = { System.out.println(it) }
#Test
fun uiPrinterIsInvoked() {
val myClass = MyClass(testUiPrinter)
myClass.foo()
// can I verify that testUiPrinter has been invoked?
}
}
You may want to check out the Model-View-Presenter architecture. Its purpose is to hide the Android framework behind an abstract View interface which a purely Java Presenter can interact with. In your example:
interface ViewInterface {
fun printError(error: String)
}
class MyPresenter(private val view: ViewInterface) {
fun foo() {
// do some stuff (testable stuff)
view.printError("Printing from foo()!")
// do some more (testable) stuff
}
}
class MyPresenterTest() { // Test using Mockito to mock the abstract view
private val view = mock(ViewInterface::class.java)
private val presenter = MyPresenter(view)
#Test
fun printsError() {
// set up preconditions
presenter.foo()
verify(view).printError("Printing from foo()!")
}
}
Your concrete view will generally be an Android Activity, Fragment, or View which implements the view interface. Notice MyPresenter only expects the abstract view and does not need knowledge of the framework-dependent operations.
class MyActivity : Activity(), ViewInterface {
// ...
override fun printError(error: String) {
textView.text = error // For example
}
// ...
}
This can be achieved by mocking the higher-order function as higher-order functions are objects unless inlined.
#Mock
val testUiPrinter: (String) -> Unit
#Test
fun uiPrinterIsInvoked() {
val myClass = MyClass(testUiPrinter)
myClass.foo()
verify(testUiPrinter).invoke("Printing from foo!")
}