Function returning ad-hoc object in Kotlin - kotlin

Currently I have a private function which returns a Pair<User, User> object. The first user is the sender of something, the second user is the receiver of that thing.
I think this Pair<User, User> is not enough self explanatory - or clean if you like - even though it's just a private function.
Is it possible to return with an ad-hoc object like this:
private fun findUsers(instanceWrapper: ExceptionInstanceWrapper): Any {
return object {
val sender = userCrud.findOne(instanceWrapper.fromWho)
val receiver = userCrud.findOne(instanceWrapper.toWho)
}
}
and use the returned value like this:
// ...
val users = findUsers(instanceWrapper)
users.sender // ...
users.receiver // ...
// ...
?
If not, what's the point of ad-hoc object in Kotlin?

Since the type can not be denoted in the language, use return type inference:
class Example {
private fun findUsers(instanceWrapper: ExceptionInstanceWrapper) =
object {
val sender = userCrud.findOne(instanceWrapper.fromWho)
val receiver = userCrud.findOne(instanceWrapper.toWho)
}
fun foo() = findUsers(ExceptionInstanceWrapper()).sender
}
Another option would be to devise a data class:
class Example {
private data class Users(val sender: User, val receiver: User)
private fun findUsers(instanceWrapper: ExceptionInstanceWrapper): Users {
return Users(
sender = userCrud.findOne(instanceWrapper.fromWho),
receiver = userCrud.findOne(instanceWrapper.toWho)
)
}
fun foo() = findUsers(ExceptionInstanceWrapper()).sender
}

Simply define your function as a lambda.
Here's simple object I've just written as an example in another context:
private val Map = {
val data = IntArray(400)
for (index in data.indices) {
data[index] = index * 3
}
object {
val get = { x: Int, y: Int ->
data[y * 20 + x]
}
}
}
fun main() {
val map = Map()
println(map.get(12,1))
}
Unfortunately, you cannot assign a type name, so it can be used as a return value but not as an argument. Maybe they'll make this possible so we can finally do OOP JS style.
Alternatively, they could implement object types equivalent to function types but that could end up being too wordy. You could then do a typedef but that would actually just be a kind of class definition 😅

Another option is to have a generic class for return types:
data class OutVal<T>(private var v: T?) {
fun set(newVal: T) {
v = newVal
}
fun get() = v
}
Usage example:
private fun findUsers(instanceWrapper: ExceptionInstanceWrapper,
sender: OutVal<String>, receiver: OutVal<String>) {
sender.set(userCrud.findOne(instanceWrapper.fromWho))
receiver.set(userCrud.findOne(instanceWrapper.toWho))
}
val sender = OutVal("")
val receiver = OutVal("")
findUsers(instanceWrapper, sender, receiver)
sender.get() // ...
receiver.get() // ...

Related

Kotlin: How to define a variable whose type depends on the input?

I have a function in Kotlin which takes a particular string as input. Depending on the input, I want to create a variable of a specific type and do some computations on it.
For example,
fun compute(input: String): Any{
if(input=="2d"){
var point: Point2D;// Points2D - x: int, y: int
//initilize and do some computations
return point.findDistanceFromOrigin()
}else if(input=="2d-1"){
var point: Point2DWithP1AsOrigin;// Point2DWithP1AsOrigin - x: int, y: int
//initilize and do some computations
return point.findDistanceFromOrigin()
}else if(input=="2d-2"){
var point: Point2DWithP2AsOrigin;
//initilize and do some computations
return point.findDistanceFromOrigin()
}
.
.
.
}
You can see in the above example, I want to initilize the type of point depending on the input and do computation and return.
All the if-else conditions have the same code except for the definition of the variable. How can I put all this in a single block with something like this:
var point: if(input=="2d) Point2D::class else if(input=="2d-1") Point2DWithP1AsOrigin::class.....
How can I do that?
You could do something like this
fun compute(input: String): Any{
val point: MyPoint = when(input) {
"2d" -> Point2D()
"2d-1" -> Point2DWithP1AsOrigin()
"2d-2" -> Point2DWithP2AsOrigin()
else -> Point2D() //fallback is necessary
}
//initilize and do some computations
return point.findDistanceFromOrigin()
}
But then it's essential that all those classes share the same interface. Because they need to have the same methods in order to do the same operations on them.
For example like this:
class Point2D : MyPoint {
override fun findDistanceFromOrigin() = 5
}
class Point2DWithP1AsOrigin : MyPoint{
override fun findDistanceFromOrigin() = 6
}
class Point2DWithP2AsOrigin : MyPoint{
override fun findDistanceFromOrigin() = 7
}
interface MyPoint {
fun findDistanceFromOrigin() : Int
}
You can store constructor references and then invoke required one
fun main() {
val constructors = mapOf(
"2d" to ::Point2D,
"2d-1" to ::Point2DWithP1AsOrigin,
"2d-2" to ::Point2DWithP2AsOrigin,
)
val type = "2d-2"
val constructor = constructors[type] ?: throw IllegalArgumentException("$type not supported")
val point = constructor()
println(point::class)
}
Output
class Point2DWithP2AsOrigin

How to address a getter from inside the class in Kotlin

Consider following Kotlin-Code:
class Foo(input: Int) {
private var someField: Int = input
get() = -field
set(value) {
field = -value
}
fun bar() {
println(someField)
}
}
fun main() {
Foo(1).bar()
}
This prints -1 in the console which means that inside method bar() someField references the attribute and not the corresponding getter. Is there a way that allows me to use the get()-method as if I was referencing this field from outside?
Perhaps you could track the "raw" value separately from the negative value? Something like this:
class Foo(input: Int) {
private var _someField: Int = input
var someField: Int
get() = -_someField
set(value) {
_someField = -value
}
fun bar() {
println(someField)
}
}
Now the class internals can reference _someField to deal directly with the raw value, while outside clients can only "see" someField.

Pass a list of functions with different parameters in Kotlin

I have a class that calls functions depending on events. Events are emitted from sockets. I should catch these events, parse JSON and respond (call a corresponding function). For instance, {"event_name": "message", "data": {"text": "dfgfdgfdg", "sender": "dsfdsfs"}}
fun listener(jsonString: String, methodsMap: Map<String, () -> Unit>) {
val json = JSONObject(jsonString)
val data = json.getJSONObject("data")
when (json.get("event_name")) {
"update" -> {
val count = data.getInt("count")
methodsMap["update"]?.invoke(count) // 1 parameter.
}
"message" -> {
val message = data.getString("text")
val sender = data.getString("sender")
methodsMap["message"]?.invoke(message, sender) // 2 parameters.
}
}
}
So, I cannot create one method that calls functions with different parameters. How to do this?
Since you are already have if-then logic in listener, having the functions in a Map is of questionable value and it forces you to to deal with the fact that your functions are of different types. If it is parametrisation of listener you are after, perhaps this (simplified example code that skips JSON) is sufficient:
class UpdateHandler {
fun update(n: Int) = println("update ( $n )")
}
class MessageHandler {
fun message(s1: String, s2: String) = println("message ( $s1 $s2 )")
}
fun listener(jsonString: String, updateF: (Int) -> Unit, messageF: (String, String) -> Unit) {
when (jsonString) {
"update" -> updateF(73)
"message" -> messageF("message", "sender")
}
}
fun main() {
val updateHandler = UpdateHandler()
val messageHandler = MessageHandler()
val listener = { json: String -> listener(json, updateHandler::update, messageHandler::message) }
listener("update") // prints: update ( 73 )
listener("message")// prints: message ( message sender )
}
First, I wanted to use a list of parameters in each function, but it leads to poor type verification during compilation. Also I wanted to assign vararg instead of List, but couldn't.
fun listener(jsonString: String, methodsMap: Map<String, (List<Any>) -> Unit>) {
...
methodsMap["update"]?.invoke(listOf(count)) // 1 parameter.
...
methodsMap["message"]?.invoke(listOf(message, sender)) // 2 parameters.
}
This is a poor solution. Bugs may occur, we should remember to change methodsMap in every class that uses listener when we change any event.
Second, I tried to use sealed classes. This is not so simple.
Third, I tried to use interface. We know that callbacks are usually made with interfaces. We can even merge interfaces in Kotlin. So, this can be a solution to a problem (but not to a question).
fun listener(jsonString: String, callback: EventListener) {
val json = JSONObject(jsonString)
val data = json.getJSONObject("data")
when (json.get("event_name")) {
"update" -> {
val count = data.getInt("count")
callback.onUpdate(count)
}
"message" -> {
val text = data.getString("text")
val sender = data.getString("sender")
callback.onNewMessage(text, sender)
}
}
}
interface EventListener {
fun onUpdate(count: Int)
fun onNewMessage(text: String, sender: String)
}
Then we can call listener outside of the class and pass any callbacks we like.

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

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