Kotlin: Can I overwrite a function with another function? (like override) - kotlin

I'm a Kotlin beginner.
I am not sure if the way I try is correct.
Now I want to override and capturing variables.
Suppose this is a method of SOMETHING class that can be overridden:
fun whoAreYou() {}
And this is my function:
fun thisFuntionsIs(): ()->Unit {
var i = 0
println("It's parent Function!")
return { println("It's child Function! ${i++}") }
}
Now I tried to override the existing function with the new one:
fun whoAreYou() = thisFuntionsIs() // Suppose used the override keyword
Now when I run this function it prints out a "parent" message every time.
This is not what I wanted.☹
If whoAreYou was a property, not a method, it would have been worked I wanted.
class SOMETHING {
var whoAreYou = ()->{} // If it was a property...
// fun whoAreYou() {} // But the current situation is
}
SOMETHING.whoAreYou = thisFuntionsIs()
SOMETHING.whoAreYou() // Yea~ I wanted that
Is there a solution? Or am I totally wrong? Please help me.

In order to override, you need to make your parent class and function open, then override the function in an extended class:
open class Parent {
protected var counter = 0;
open fun whoAreYou() = "It's parent Function!"
}
class Child : Parent() {
override fun whoAreYou() = "It's child Function! ${counter++}"
}
fun main() {
val parent: Parent = Parent()
val child: Parent = Child()
println(parent.whoAreYou()) // It's parent Function!
println(child.whoAreYou()) // It's child Function! 0
println(child.whoAreYou()) // It's child Function! 1
println(child.whoAreYou()) // It's child Function! 2
}

The code works. Maybe you just misinterpret results. Slightly modified version:
fun main(args: Array<String>) {
val x = SOMETHING()
x.whoAreYou = thisFuntionsIs()
x.whoAreYou()
x.whoAreYou()
}
class SOMETHING {
var whoAreYou = fun() {
System.out.println("It's parent Function!")
}
}
fun thisFuntionsIs(): () -> Unit {
var i = 0
System.out.println("It's Function!")
return { System.out.println("It's lambda! ${i++}") }
}
Output:
> It's Function!
> It's lambda! 0
> It's lambda! 1
The line x.whoAreYou = thisFuntionsIs() means that thisFuntionsIs is called and x.whoAreYou is assigned to anonymous function return by thisFuntionsIs.

Related

why my data is coming as null or default in ui from view model in kotlin?

I set up mvvm structure and call two functions in viewmodel. Functions return values, but these values ​​always come as values ​​that I define as null or default.
Why can't I access my data in the view model in the UI?
I can see the data properly in the view model
hear is my code
my ui
if (viewModel.isDialogShown) {
AlertDialog(
onDismiss = {
viewModel.onDismissClick()
},
onConfirm = {
println("First"+viewModel.getFirstConversionRateByCurrency(viewModel.dropDownMenuItem1))
println("SECOND:"+viewModel.getSecondConversionRateByCurrency(viewModel.dropDownMenuItem2))
}
)
}
If the user says confirm in the alert dialog in my UI, these functions are called and I print the returned values ​​for testing purposes, but because I define null as default in the viewmodel, it always comes null.
my view model
#HiltViewModel
class ExchangeMainViewModel #Inject constructor(
private val getConversionRateByCurrencyUseCase: GetConversionRateByCurrencyUseCase
) : ViewModel() {
var second : Double?=null
var first : Double? = null
fun getFirstConversionRateByCurrency(currency:String) : String {
viewModelScope.launch {
first = getConversionRateByCurrencyUseCase.getConversionRateByCurrency(currency)
}
return first.toString()
}
fun getSecondConversionRateByCurrency(currency:String) :String {
viewModelScope.launch {
second = getConversionRateByCurrencyUseCase.getConversionRateByCurrency(currency)
}
return second.toString()
}
}
Also, I defined the viewmodel in ui as you can see the below like this, could it be because of this?
#Composable
fun DropDownMenu(
viewModel: ExchangeMainViewModel = hiltViewModel()
) {
The result in the console is as follows
All those functions your are calling are executing a coroutine from viewModelScope.launch{…} and at the time you launched them you immediately return a value from the method return.xxx.toString() where the xxx (first and second) doesn't have a value yet since what you are expecting is coming from a concurrent execution not a sequential one.
viewModelScope.launch { // launch me separately and wait for any value that will set the `first`
first = getConversionRateByCurrencyUseCase.getConversionRateByCurrency(currency)
}
// return from this function now with a null value, since it was initialized as null
return first.toString()
This is a rough implementation, though I'm not sure if this would work, but this should give you a headstart
Your new ViewModel
#HiltViewModel
class ExchangeMainViewModel #Inject constructor(
private val getConversionRateByCurrencyUseCase: GetConversionRateByCurrencyUseCase
) : ViewModel() {
var conversionValue by mutableStateOf<ConversionValues?>(null)
fun getFirstConversionRateByCurrency(currency:String) {
viewModelScope.launch {
val first = getConversionRateByCurrencyUseCase.getConversionRateByCurrency(currency)
val second = getConversionRateByCurrencyUseCase.getConversionRateByCurrency(currency)
conversionValue = ConversionValues(first, second)
}
}
}
the Data Class for first and second
data class ConversionValues(
val first : Double,
val second: Double
)
and your composable
#Composable
fun DropDownMenu(
viewModel: ExchangeMainViewModel = hiltViewModel()
) {
val conversionValue = vieModel.conversionValue
if (viewModel.isDialogShown) {
AlertDialog(
onDismiss = {
viewModel.onDismissClick()
},
onConfirm {
println("First" + conversionValue.first)
println("SECOND:"+conversionValue.second)
}
)
}
}

How to express in Kotlin "assign value exactly once on the first call"?

Looking for a natural Kotlin way to let startTime be initialized only in a particular place and exactly once.
The following naive implementation have two problems:
it is not thread safe
it does not express the fact "the variable was or will be assigned exactly once in the lifetime of an Item instance"
class Item {
var startTime: Instant?
fun start(){
if (startTime == null){
startTime = Instant.now()
}
// do stuff
}
}
I believe some kind of a delegate could be applicable here. In other words this code needs something similar to a lazy variable, but without initialization on first read, instead it happens only after explicit call of "touching" method. Maybe the Wrap calls could give an idea of possible implementation.
class Wrap<T>(
supp: () -> T
){
private var value: T? = null
private val lock = ReentrantLock()
fun get(){
return value
}
fun touch(){
lock.lock()
try{
if (value == null){
value = supp()
} else {
throw IllegalStateExecption("Duplicate init")
}
} finally{
lock.unlock()
}
}
}
How about combining AtomicReference.compareAndSet with a custom backing field?
You can use a private setter and make sure that the only place the class sets the value is from the start() method.
class Item(val value: Int) {
private val _startTime = AtomicReference(Instant.EPOCH)
var startTime: Instant?
get() = _startTime.get().takeIf { it != Instant.EPOCH }
private set(value) = check(_startTime.compareAndSet(Instant.EPOCH, value)) { "Duplicate set" }
fun start() {
startTime = Instant.now()
}
override fun toString() = "$value: $startTime"
}
fun main() = runBlocking {
val item1 = Item(1)
val item2 = Item(2)
println(Instant.now())
launch { println(item1); item1.start(); println(item1) }
launch { println(item1) }
delay(1000)
println(item2)
item2.start()
println(item2)
println(item2)
item2.start()
}
Example output:
2021-07-14T08:20:27.546821Z
1: null
1: 2021-07-14T08:20:27.607365Z
1: 2021-07-14T08:20:27.607365Z
2: null
2: 2021-07-14T08:20:28.584114Z
2: 2021-07-14T08:20:28.584114Z
Exception in thread "main" java.lang.IllegalStateException: Duplicate set
I think your Wrap class is a good starting point to implement this. I would definitely make it a property delegate and touch() could be much simplified:
fun touch() {
synchronized(this) {
check(value == null) { "Duplicate init" }
value = supp()
}
}
Then you can remove lock. But generally, this is a good approach.
If you would like to reuse lazy util from stdlib then you can do this by wrapping it with another object which does not read its value until asked:
class ManualLazy<T : Any>(private val lazy: Lazy<T>) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T? {
return if (lazy.isInitialized()) lazy.value else null
}
fun touch() {
lazy.value
}
}
class Item {
private val _startTime = ManualLazy(lazy { Instant.now() })
val startTime: Instant? by _startTime
fun start(){
_startTime.touch()
}
}
Of course, depending on your needs you can implement it in a much different way, using a similar technique.
This may be considered exploiting or hacking lazy util. I agree and I think Wrap approach is a better one.

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

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
}
}

Use a class from a list of generic interface

I am trying to implement a QueryBus. Basically, I want to register a list of QueryHandlers. Each QueryHandler implements a handle method defined by an interface. Each QueryHandler is associated to a Query. I want to be able to retrieve a QueryHandler using the Query and call handle on it.
The thing is the handle has to be generic because each QueryHandler handles a Query differently. They all take a dedicated Query and may return whatever they want.
interface Query<R>
interface QueryHandler<R, Q : Query<R>> {
fun handle(query: Q): R
fun listenTo(): String
}
// DTOs
data class BookDto(val name: String)
// List books query
data class ListBooksQuery(val page: Int = 1): Query<List<BookDto>>
class ListBooksQueryHandler: QueryHandler<List<BookDto>, ListBooksQuery> {
override fun handle(query: ListBooksQuery): List<BookDto> {
return listOf(BookDto("Dune"), BookDto("Dune II"))
}
override fun listenTo(): String = ListBooksQuery::class.toString()
}
// Get book query
data class GetBookQuery(val name: String): Query<BookDto?>
class GetBookQueryHandler: QueryHandler<BookDto?, GetBookQuery> {
override fun handle(query: GetBookQuery): BookDto {
return BookDto("Dune")
}
override fun listenTo(): String = GetBookQuery::class.toString()
}
// Run it!
fun main(args: Array<String>) {
// Initializing query bus
val queryHandlers = mapOf(
with(ListBooksQueryHandler()) {this.listenTo() to this},
with(GetBookQueryHandler()) {this.listenTo() to this}
)
val command = ListBooksQuery()
val result = queryHandlers[command::class.toString()].handle(command)
// Should print the list of BookDto
print(result)
}
I don't even know if its possible, to be honest.
UPDATE 1:
I changed the usage example in the main to show what I am really trying to do. The List was for (bad?) demonstration purpose. I want to store the QueryHandlers and retrieve them from a map.
Additional resources:
Here is what I really want to do:
https://gist.github.com/ValentinTrinque/76b7a32221884a46e657090b9ee60193
UPDATE I've read your gist and tried to come up with a solution that will provide a clean interface to the user of the QueryBusMiddleware.
Note that I used objects instead of classes for the QueryHandler implementations, which felt more natural to me (since there is only one possible entry in the map for each Query implementation).
interface Query<R>
interface QueryHandler<R, Q: Query<R>> {
fun handle(query: Q): R
fun listenTo(): String
}
// DTOs
data class BookDto(val name: String)
// List books query
data class ListBooksQuery(val page: Int = 1): Query<List<BookDto>>
object ListBooksQueryHandler: QueryHandler<List<BookDto>, ListBooksQuery> {
override fun handle(query: ListBooksQuery): List<BookDto> {
return listOf(BookDto("Dune"), BookDto("Dune II"))
}
override fun listenTo(): String = ListBooksQuery::class.toString()
}
// Get book query
data class GetBookQuery(val name: String): Query<BookDto?>
object GetBookQueryHandler: QueryHandler<BookDto?, GetBookQuery> {
override fun handle(query: GetBookQuery): BookDto {
return BookDto("Dune")
}
override fun listenTo(): String = GetBookQuery::class.toString()
}
// Run it!
fun main(args: Array<String>) {
// Initializing query bus
val queryHandlers = listOf(
ListBooksQueryHandler,
GetBookQueryHandler
)
val dispatcher: QueryBusMiddleware = QueryDispatcherMiddleware(queryHandlers)
// Calling query bus
val query = ListBooksQuery()
// Result should be List<BookDto>
val result = dispatcher.dispatch(query)
print(result)
}
interface QueryBusMiddleware {
fun <R, Q : Query<R>> dispatch(query: Q): R
}
class QueryDispatcherMiddleware constructor(handlers: List<QueryHandler<*, *>>) : QueryBusMiddleware {
private val handlers = HashMap<String, QueryHandler<*, *>>()
init {
handlers.forEach { handler -> this.handlers[handler.listenTo()] = handler }
}
override fun <R, Q : Query<R>> dispatch(query: Q): R {
val queryClass = query::class.toString()
val handler = handlers[queryClass] ?: throw Exception("No handler listen to the query: $queryClass")
return handler::class.members.find { it.name == "handle" }!!.call(handler, query) as R
}
}

How to get kotlin function's caller

With this example:
open class Parent {
fun some():Parent {
return this;
}
}
class A : Parent(){
val name:String? = null;
}
But then this code results in an error:
val a = A().some().some()
a.name // ERROR
EDITOR NOTE: based on comments of the author to answers below, the question is NOT about referencing a.name but really is about something like "how do I get the instance of the class or its name that first started the chain of method calls". Read all comments below until the OP edits this for clarity.
my final goal is to return caller's type and can call this caller's instance property, no more as , no more override, any idea?
Just like java, you can use stackTrace's getMethodName(). Refer to the kotlin doc.
Actially your example is working(if you add open keyword because all classes in Kotlin are final by default:
A.kt
open class A {
fun some(): A {
return this
}
}
B.kt
class B : A() {
val test = "test"
}
And usage
val tmpB = (B().some().some() as B)
val test = tmpB.test
Edited:
It because function some() return parent class which doesn't have child class property. So you need to cast it to child class.(Update code)
open class Parent{
open fun foo(): Parent {
return this;
}
}
This is your Parent class. Parent class has a method named foo(). foo() is a method of class A which will return the instance of it's own class. We must have to open the class and method because by default their visibility modifier is final.
class A : Parent() {
override fun foo(): A { return this }
}
This is a class named A which extends Parent class. foo() is a method of class A which will return the instance of it's own class.
We will call it like this:
var a = A().foo().foo()
Your class always return Parent instance. This class do not have any field with the name name. To do that you have 2 ways:
The first:
open class Parent{
fun some():Parent{
return this
}
}
class A :Parent(){
val name:String? = null
}
fun main() {
val a = (A().some().some() as A)
a.name = "";
}
The second:
open class Parent{
open fun some():Parent{
return this
}
}
class A :Parent(){
override fun some():A {
return this
}
val name:String? = null
}
fun main() {
val a = A().some().some()
a.name = "";
}
i have know how to do this:
#Avijit Karmakar
#Trần Đức Tâm
use inline function
inline fun <reified T:Any> some(sql: String):T {
return this as T ;
}