Hiding base class constructor parameters in Kotlin - 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)
}
...
}

Related

Delegate a function to all other interfaces

I have an interface:
interface EmployeeActions
interface SalesEmployeeActions : EmployeeActions {
fun onSaleRequest()
//..more functions
}
interface HREmployeeActions : EmployeeActions {
}
...//more EmployeeActions
Now the way I am using this in the class is basically an aggregation where I will have many of these objects and I want to call stuff on them all together.
class FakeEmployeeDb {
val employees: MutableList<EmployeeActions> = mutableListOf()
private val salesEmployees:
get() = employees.filterIsInstance<SalesEmployeeActions>()
....
val salesManager = object: SalesEmployeeAction {
fun onSaleRequest() {
salesEmployees.forEach { it.onSaleRequest() }
}
... //more functions
}
private val .... // other Managers
// also at some point employees are added using this API...
fun addEmployee(employee: EmployeeActions) {
employees.add(employee)
}
}
Question:
Is there a kotlin-y way of writing this code in a scalable way?
In the real case, the client will only call APIs on these xyzManager objects and the job of each of them is to simply pass that information down to all employees.

Allow function calls only in special context

I'm trying to write a class that only allows certain methods to be called in a lambda of one function.
Basically, I want to achieve similar behaviour to how you can only call suspend functions in a suspend context.
Right now the closest I can get is this.
class MyClass {
fun runCommands(block: CommandContext.() -> Unit) {
// do prep work
block.invoke(commandContext)
// do cleanup work
}
val commandContext = CommandContext()
inner class CommandContext {
fun commandFunc() {} // only callable from the lambda
}
}
The issues I'm having with this is I can't make CommandContext private so you could always make your own instance and run the command externally. It is also unnecessary for it to be instantiatable but I can't make an "inner object."
Any ideas on how to do this cleaner?
Outer scope should know that there is a commandFunc() method in CommandContext class (and that this class actually exists). That's why it can't be private. But you can encapsulate its implementation, effectively making it private, keeping public only its interface:
interface CommandContext {
fun commandFunc()
}
class MyClass {
fun runCommands(block: CommandContext.() -> Unit) {
// do prep work
block.invoke(CommandContextImpl)
// do cleanup work
}
private object CommandContextImpl : CommandContext {
override fun commandFunc() {} //actual implementation
}
}
//Usage:
fun main() {
MyClass().runCommands { commandFunc() }
}

Kotlin Delegation how to access class properties from delegate object

I'm trying to split some work from a giant class to provide more readability. Firstly I looked into Extension but seems like it is just creating some static functions, then delegate pattern came into my eyes.
The below code looks all right, and delegate works as if part of EnhancedProducer class.
But there is one problem that blocking me though, I don't quite get how to access the service property of EnhancedProcuder class from delegate. In my real code, there are some cases that both the original class and delegate class need to use the service variable at the same time, so I don't know if there is a way to do it.
I do understand we can probably inject service instance into both of them but I still want to find out if there is a more elegant way to makes delegate fit into EnhancedProducer class more naturally.
interface Producer {
fun produce()
}
class ProducerImpl : Producer {
override fun produce() {
// service.doSomething() how to access service here
println( "ProducerImpl")
}
}
class EnhancedProducer(private val delegate: Producer) : Producer by delegate {
// how to share this with delegate
//private val service = Service()
fun test() {
produce()
}
}
fun main() {
val producer = EnhancedProducer(ProducerImpl())
producer.test()
}
I have eventually come up with a solution that initialise ProducerImpl right after by keyword. It is so weird that all the examples that I found so far only try to inject an instance rather than providing an initialization when delegation is needed. Maybe someone knows anything about it?
interface Producer {
fun produce()
}
class ProducerImpl(val service:Service) : Producer {
override fun produce() {
service.doSomething()
println(item)
}
}
class EnhancedProducer(val service:Service) : Producer by ProducerImpl(service) {
fun test() {
produce()
}
}
fun main() {
val service = Service()
val producer = EnhancedProducer(service)
}
May use open properties in the interface:
interface Producer {
fun produce()
// two classes will use/modify this property
var service: Service
}
...
class ProducerImpl: Producer {
override var service = Service()
fun changeService() {
service.execute() // access to the interface field
}
}
...
class EnhancedProducer(private val delegate: Producer): Producer by delegate {
fun test() {
this.service // access to the interface field
delegate.service // access to the interface field
produce()
}
}
fun main() {
val producerImpl = ProducerImpl()
val producer = EnhancedProducer(producerImpl)
producerImpl.service // access to the interface field
producer.service // access to the interface field
}

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
}

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!")
}